SlideShare a Scribd company logo
1 of 97
1
Using Redux-Saga for Handling Side Effects
Igor Nesterenko
Lead Software Engineer
17.08.2018
2
Agenda
1. Problem
2. Solutions
3. redux-saga
4. Basic Concepts
5. Advanced Concepts
6. Unit Testing
7. Recommendations
8. Loose Coupled System
9. Summary
10.Future Reading
33
Problem
4
Problem
1. Side-effects are roots of errors and mistrust
• Async (aka concurrency) is hard
2. A program without side effects is useless
3. React and redux don’t solve that all issue
55
Solutions
6
Solutions
1. Custom redux middleware
2. redux-thunk (action creator)
3. redux-saga (saga)
4. redux-loop (reducer)
77
redux-saga
8
redux-saga
1. Origins of Saga Pattern
2. The Process Manager Pattern
3. redux-saga
9
Origins of Saga Pattern
10
Origins of Saga Pattern
Saga is a failure management pattern
● T - transaction
● C - compensation action
11
The Process Manager Pattern
12
The Process Manager
Sagas
ES6 generators
Saga Monitor
redux middleware
Redux Action
13
Confusions around saga pattern
1. Saga is a failure management pattern
2. redux-saga is an alternative side effect model for Redux apps
1414
Basic Concepts
15
Terms
1. Effect - is a single, atomic predefined instruction or command
(POJO)
2. Saga - collection of effects, realized in form of ES6 generator
3. Saga Middleware - redux middleware to execute sagas
4. Effect Creator - function to create effect objects
5. Channels - queues for actions
6. Helper and Untils - helper functions for day to day tasks, factory
function to wrap external IO or event channels
16
Effect and Effect Creator
put({type: 'INCREMENT'}) // => { PUT: {type:
'INCREMENT'} }
call(delay, 1000) // => { CALL: {fn:
delay, args: [1000]}}
17
Effect Creators
● take
● put
● call, apply
● fork, spawn
● cancel, canceled
● select
18
Saga Example
// Our worker Saga: will perform the async increment task
export function* incrementAsync() {
yield delay(1000)
yield put({ type: 'INCREMENT' })
}
19
Setup Saga
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(helloSaga)
const action = type => store.dispatch({type})
20
Synchronous Like Code
function* fetchProducts() {
try {
const products = yield call(Api.fetch, '/products')
yield put({ type: 'PRODUCTS_RECEIVED', products })
}
catch(error) {
yield put({ type: 'PRODUCTS_REQUEST_FAILED', error })
} finally {
if (yield cancelled())
yield put({ type: 'PRODUCTS_REQUEST_FAILED', new Error('Canceled')})
}
}
21
Pull Future Action
function* loginFlow() {
while (true) {
yield take('LOGIN')
// ... perform the login logic
yield take('LOGOUT')
// ... perform the logout logic
}
}
2222
Advanced Concepts
23
Advanced Concepts
1. Helper utils
2. Effect Combinators
3. Fork Model
4. Channels
5. External I/O
24
Helper Utils and Effect Creators
export default function* rootSaga() {
yield takeLatest('FETCH_USERS', fetchUsers)
yield takeEvery('CREATE_USER', createUser)
}
25
Effect Combinators
● Run Tasks in Parallel
● Starting Race Between Multiple Tasks
26
Effect Combinators - all
function* fetchAll() {
yield all([
call(fetchResource, 'users'), // task1
call(fetchResource, 'comments'), // task2,
call(delay, 1000)
])
}
27
Effect Combinators - race
function* fetchPostsWithTimeout() {
const {posts, timeout} = yield race({
posts: call(fetchApi, '/posts'),
timeout: call(delay, 1000)
})
if (posts)
put({type: 'POSTS_RECEIVED', posts})
else
put({type: 'TIMEOUT_ERROR'})
}
28
Effect Combinators - Not Only For Requests
function* backgroundTask() {
while (true) { ... }
}
function* watchStartBackgroundTask() {
while (true) {
yield take('START_BACKGROUND_TASK')
yield race({
task: call(backgroundTask),
cancel: take('CANCEL_TASK')
})
}
}
29
Fork Model
● fork is used to create attached fork
● spawn is used to create detached forks
● non-blocking
30
Fork Model
Fetch All
Fetch Comments
Fetch Users
main
Blocking Call
Non-blocking Call
Wait All for Terminate
31
Fork Model - Completion
function* fetchAll() {
const task1 = yield fork(fetchResource, 'users')
const task2 = yield fork(fetchResource, 'comments')
yield call(delay, 1000)
}
function* main() {
yield call(fetchAll)
}
Non-blocking
Blocking
32
Fork Model - Error PropagationFork Model
Fetch All
Fetch Comments
Fetch Users
main
Blocking Call
Non-blocking Call
Catch All Errors Catch Forks Errors
33
Fork Model - Error Propagation
try{
yield fork(watchBgTask);
yield fork(watchCheckout)
} catch (err) {
yield put({type:”CRITICAL_ERROR”});
}
34
Fork Model - Cancelation
function* main() {
while ( yield take(START_BACKGROUND_SYNC) ) {
const bgSyncTask = yield fork(bgSync)
yield take(STOP_BACKGROUND_SYNC)
yield cancel(bgSyncTask)
}
}
35
Fork Model - Detect Cancellation Inside Saga
function* bgSync() {
try {
while (true) {
yield put(actions.requestStart())
const result = yield call(someApi)
yield put(actions.requestSuccess(result))
}
} finally {
if (yield cancelled())
yield put(actions.requestFailure('Sync cancelled!'))
}
}
36
Channels
● Buffer actions from the Redux Store
● Connect take effect to external event source
● Communicate between sagas
37
Channels - Buffer Actions
Saga
F1
Fork
F2
F3
Store
Put 1
Request 1
Request 2
Request 3
Take
Put 2
Put 3
38
Channels - Buffer Actions
function* watchRequests() {
while (true) {
const {payload} = yield take('REQUEST')
yield fork(handleRequest, payload)
}
}
39
Channels - Buffer Actions
Saga StorePut 2
Request 1
Request 2
Request 3
Channel
Put 1
Put 3
Store in Buffer
40
Channels - Buffer Actions
function* watchRequests() {
const requestChan = yield actionChannel('REQUEST')
while (true) {
const {payload} = yield take(requestChan)
yield call(handleRequest, payload)
}
}
41
Channels - Buffer Actions
function* watchRequests() {
const requestChan = yield actionChannel('REQUEST')
while (true) {
const {payload} = yield take(requestChan)
yield call(handleRequest, payload)
}
}
42
Channels - eventChannel
Socket Channel Saga ChanneleventChannel
as argument
creates
My Saga
take, put● emmiter(payload)
● emmiter(END)
43
Channels - eventChannel
export function* watchOnPings() {
const socket = yield call(createWebSocketConnection)
const socketChannel = yield call(createSocketChannel, socket)
while (true) {
const payload = yield take(socketChannel)
yield put({ type: INCOMING_PONG_PAYLOAD, payload })
yield fork(pong, socket)
}
}
44
Channels - eventChannel
function* pong(socket) {
yield call(delay, 5000)
yield apply(socket, socket.emit, ['pong'])
}
45
Channels - Communication Between Sagas
Fork 1
Fork 2
Fork 3
Saga
Shared Channel
aka load balancing
Push message to free fork
create
46
Channels - Communication Between Sagas
function* watchRequests() {
const chan = yield call(channel)
for (var i = 0; i < 3; i++) {
yield fork(handleRequest, chan)
}
while (true) {
const {payload} = yield take('REQUEST')
yield put(chan, payload)
}
}
47
Channels - Communication Between Sagas
function* handleRequest(chan) {
while (true) {
const payload = yield take(chan)
// process the request
}
}
4848
Unit Testing
49
Unit Testing
● Mockless unit testing
● Saga Helpers
50
Unit Testing - Iterate and Compare
function* incrementAsync() {
yield delay(1000)
yield put({ type: 'INCREMENT' })
}
51
Unit Testing - Iterate and Compare
test('incrementAsync Saga test', (assert) => {
const gen = incrementAsync()
// now what ?
});
52
Unit Testing - Iterate and Compare
gen.next() //=>{ done: false, value: <result ... delay(1000)> }
gen.next() //=>{ done: false, value: <result ... put({...})> }
gen.next() //=>{ done: true, value: undefined }
53
Unit Testing - Iterate and Compare
test('incrementAsync Saga test', (assert) => {
const gen = incrementAsync()
assert.deepEqual(
gen.next().value,
call(delay, 1000),
'incrementAsync Saga must call delay(1000)'
)
// ....
});
54
Unit Testing - Different Branches
function* doStuffThenChangeColor() {
yield put(doStuff());
yield put(doStuff());
const action = yield take(CHOOSE_NUMBER);
if (action.payload.number % 2 === 0) {
yield put(changeUI('red'));
} else {
yield put(changeUI('blue'));
}
}
55
Unit Testing - Clonable Generator
test('doStuffThenChangeColor', assert => {
const gen = cloneableGenerator(doStuffThenChangeColor)();
gen.next(); // DO_STUFF
gen.next(); // DO_STUFF
gen.next(); // CHOOSE_NUMBER
// ...
});
56
Unit Testing - Clonable Generator - First Branch
const gen = cloneableGenerator(doStuffThenChangeColor)();
// ...
const clone = gen.clone();
assert.deepEqual(
clone.next(chooseNumber(2)).value,
put(changeUI('red')),
'should change the color to red'
);
57
Unit Testing - Clonable Generator - Second Branch
const gen = cloneableGenerator(doStuffThenChangeColor)();
// ...
const otherClone = gen.clone();
assert.deepEqual(
otherClone.next(chooseNumber(3)).value,
put(changeUI('blue')),
'should change the color to blue'
);
58
Unit Testing - Clonable Generator
test('doStuffThenChangeColor', assert => {
const gen = cloneableGenerator(doStuffThenChangeColor)();
gen.next(); // DO_STUFF
gen.next(); // DO_STUFF
gen.next(); // CHOOSE_NUMBER
// ...
});
59
Unit Testing - Fork Effect
function* main() {
while ( yield take(START_BACKGROUND_SYNC) ) {
const bgSyncTask = yield fork(bgSync)
yield take(STOP_BACKGROUND_SYNC)
yield cancel(bgSyncTask)
}
}
60
Unit Testing - Fork Effect
expect(generator.next().value).toEqual(take(START_BG_SYNC));
expect(generator.next({ type: 'START_BG_SYNC' }).value).toEqual(fork(bgSync));
const mockTask = createMockTask();
expect(generator.next(mockTask).value).toEqual(take(STOP_BACKGROUND_SYNC));
expect(generator.next().value).toEqual(cancel(mockTask));
6161
Recommendations
62
Recommendations
1. Code Smells
2. Integration with React Component
3. Identify Core Flows
4. Invest in error-handling
5. Extract Reusable Saga
6. Unit Testing strategy
63
Code Smells
1.Avoid Routing
2.Avoid Reducer Logic
64
Code Smells - Routing in Sagas
// ...
import { push } from 'react-router-redux';
export default function* handleProductRedirect() {
const productId = yield select(getRouterProductId);
yield put(push(`/checkout/product/${productId}`));
}
65
Code Smells - Reducer Logic in Sagas
export function* watchForSomething() {
while (true) {
const {payload: {oneThing, anotherThing}} = yield take(SOME_THING);
yield put(DO_ONE_THING, oneThing);
yield put(DO_ANOTHER_THING, anotherThing);
}
}
66
Code Smells - Reducer Logic in Sagas
● Data Massaging
● switch for action.type ...
● Something other then Side-Effect
67
Extract Reusable Saga
export default function standartRequest(request, success, failure) {
return function* requestHandlingSaga(action) {
try {
const response = yield call(request, action.payload);
yield put(success(response));
} catch (error) {
yield put(failure(error));
}
};
}
68
Extract Reusable Saga
const handleEntityRequest = standartRequest(
Api.fetchEntity
ENTITY_REQUEST_SUCCESS,
ENTITY_REQUEST_ERROR
)
69
Integration with React Component
● componentDidMount - initialize sub-flow
● componentWillUnmount - teardown sub-flow
● Combine with Routing
● Sync with bootstrap of application
70
Combine With Routing
• /entities/ -> EntitiesRoute - dispatch list request
• /entities/ -> EntitiesList
• /entities/:id -> EntityRoute - dispatch single entity
●/entities/:id -> Entity
●/entities/:id/edit -> EntityEdit - dispatch save
71
Combine With Routing
export default function* watchEntities() {
yield takeLatest(ENTITES_REQUEST,handleEntitiesRequest);
yield takeLatest(ENTITY_REQUEST,handleEntityRequest);
yield takeLatest(ENTITY_SAVE_REQUEST,handleEntitySaveRequest);
}
72
Sync with Application Bootstrap
export default function* watchEntities() {
yield takeLatest(ENTITES_REQUEST, runAfterAuth(handleEntitysRequest)),
yield takeLatest(ENTITY_REQUEST, runAfterAuth(handleEntityRequest));
yield takeLatest(ENTITY_SAVE_REQUEST, handleEntitySaveRequest);
}
73
Sync with Application Bootstrap
export default function* runAfterAuth(handler) {
return function* (action){
const isAuthenticated = yield select(isAppAuthDone);
if (!isAuthenticated) {
yield take(APP_AUTH_SUCCESS);
}
yield call(handler, action)
}
}
74
Invest in Error Handling
1. Acton Error Naming Convention
• like “*_ERROR” postfix in actions naming
2. Unified way to make requests, I/O
3. Logger and some UI to show error to the user
75
Error Handling
export default function* rootSaga() {
try {
yield all([
watchAuth(),
watchEntities()
])
} catch (e) {
logger.error(e);
yield put(errorCritical(e));
}
}
76
Issues with stacktrace
77
babel-plugin-redux-saga
78
Unit Testing Strategy
1. Start from covering top flows for example
• must have watchAuth, watchCheckout
• nice to have watchEntities
2. Cover reusable sagas like standartRequest, runAfterAuth
7979
Loose Coupling
80
Coupling
8181
Summary
82
Summary
1. Inspired by Saga pattern, however it’s not exact implementation of Saga
pattern
2. Provides constraints to handle side-effects in one place
3. Allows maintainable unit testing of side-effect (without mocking)
4. Saga works great for side-effects, but produces code smells if used for
other tasks like routing, data massaging (aka reducers logic)
8383
Future Reading
84
Future Reading
● Origins
○ Sagas - original paper
○ Confusion about Saga pattern
○ Clarifying the Saga pattern
○ Communicating Sequential Processes
● redux-saga
○ Saga ? Why not CSP ?
○ External Resources
● Other Domains
○ Applying Saga Pattern
○ Sagas
● Unit Testing
○ Mocking is a Code Smell
85
Questions ?
86
Thank you
8787
Side Effects
88
Side-Effects
● State/Assignments
● Read/Write Data
● Communicate Over Network
● Raise Exception
● DOM
In computer science, a function or expression is said to have a
side effect if, in addition to producing a value, it also modifies
some state or has an observable interaction with calling
functions or the outside world
89
Give Me a Label
const label = await this.getLabel();
90
May Launch Missiles
async function getLabel () {
const val = Math.random();
if (val > 0.5){
await launchMissles();
return `foo foo ${val}`
}
return `blah blah ${val}`;
}
91
Why should I care about side effects ?
“Side effects are lies. Your function promises to do one thing,
but it also does other hidden things...they are devious and
damaging mistruths that often result in strange temporal
couplings and order dependencies.”
Clean Code, Robert Martin
92
Things to remember
● A program without side effects is useless
● Side effects are neither evil nor taboo
● The key is to
○ limit side effects
○ clearly identify them
○ avoid scattering them throughout the code.
93
Minuses
● issues with stacktrace
● more boilerplate code
● structuring sagas
● learning curve
94
Pluses
● side-effects isolated in one place
● maintainable code (unit testable)
● loosely coupled system
9595
Saga Pitch
96
Basics Concepts
1. Separate Instructions from Execution
2. Use ES6 generator to define set of instructions
3. Use redux middleware to execute instructions
4. Execution works with `pull-future-actions` approach
97
Saga
1. Improve Loose Coupling (SR, Component and Actions)
2. Something on top of async/await, Observables
3. Maintainable Unit Testing (without mocks)
4. Makes important business flows explicitly defined in code
5. More explicit error handling techniques

More Related Content

What's hot

Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlinintelliyole
 
Parboiled explained
Parboiled explainedParboiled explained
Parboiled explainedPaul Popoff
 
Redux training
Redux trainingRedux training
Redux trainingdasersoft
 
Advanced javascript
Advanced javascriptAdvanced javascript
Advanced javascriptDoeun KOCH
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)Scott Wlaschin
 
Concurrency in Golang
Concurrency in GolangConcurrency in Golang
Concurrency in GolangOliver N
 
Programación Funcional 101 con Scala y ZIO 2.0
Programación Funcional 101 con Scala y ZIO 2.0Programación Funcional 101 con Scala y ZIO 2.0
Programación Funcional 101 con Scala y ZIO 2.0Jorge Vásquez
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Domenic Denicola
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Scott Wlaschin
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized projectFabio Collini
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented ProgrammingScott Wlaschin
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Scott Wlaschin
 
Asynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & PromisesAsynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & PromisesHùng Nguyễn Huy
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...Philip Schwarz
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)Scott Wlaschin
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Scott Wlaschin
 

What's hot (20)

Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 
Parboiled explained
Parboiled explainedParboiled explained
Parboiled explained
 
Redux training
Redux trainingRedux training
Redux training
 
Advanced javascript
Advanced javascriptAdvanced javascript
Advanced javascript
 
React & Redux
React & ReduxReact & Redux
React & Redux
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)
 
Concurrency in Golang
Concurrency in GolangConcurrency in Golang
Concurrency in Golang
 
Programación Funcional 101 con Scala y ZIO 2.0
Programación Funcional 101 con Scala y ZIO 2.0Programación Funcional 101 con Scala y ZIO 2.0
Programación Funcional 101 con Scala y ZIO 2.0
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
Rxjs ngvikings
Rxjs ngvikingsRxjs ngvikings
Rxjs ngvikings
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Asynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & PromisesAsynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & Promises
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 

Similar to Using Redux-Saga for Handling Side Effects

Matteo Collina | Take your HTTP server to Ludicrous Speed | Codmeotion Madrid...
Matteo Collina | Take your HTTP server to Ludicrous Speed | Codmeotion Madrid...Matteo Collina | Take your HTTP server to Ludicrous Speed | Codmeotion Madrid...
Matteo Collina | Take your HTTP server to Ludicrous Speed | Codmeotion Madrid...Codemotion
 
Asyc flow control with javascript generators - redux-saga
Asyc flow control with javascript generators - redux-sagaAsyc flow control with javascript generators - redux-saga
Asyc flow control with javascript generators - redux-sagaPedro Solá
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesAnkit Rastogi
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleThierry Wasylczenko
 
Jdk 7 4-forkjoin
Jdk 7 4-forkjoinJdk 7 4-forkjoin
Jdk 7 4-forkjoinknight1128
 
Recompacting your react application
Recompacting your react applicationRecompacting your react application
Recompacting your react applicationGreg Bergé
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsEvangelia Mitsopoulou
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSAdam L Barrett
 
What's new in WorkManager-Andri Suranta Ginting (Product Engineer-Gojek)
What's new in WorkManager-Andri Suranta Ginting (Product Engineer-Gojek)What's new in WorkManager-Andri Suranta Ginting (Product Engineer-Gojek)
What's new in WorkManager-Andri Suranta Ginting (Product Engineer-Gojek)DicodingEvent
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: ServersidenessWebExpo
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every dayVadym Khondar
 
Redux Deep Dive - ReactFoo Pune 2018
Redux Deep Dive - ReactFoo Pune 2018Redux Deep Dive - ReactFoo Pune 2018
Redux Deep Dive - ReactFoo Pune 2018Aziz Khambati
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestPavan Chitumalla
 
Android Loaders : Reloaded
Android Loaders : ReloadedAndroid Loaders : Reloaded
Android Loaders : Reloadedcbeyls
 
React. Redux. Real world.
React. Redux. Real world.React. Redux. Real world.
React. Redux. Real world.Rost Galkin
 
Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)
Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)
Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)Ontico
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in GolangBo-Yi Wu
 

Similar to Using Redux-Saga for Handling Side Effects (20)

Side effects-con-redux
Side effects-con-reduxSide effects-con-redux
Side effects-con-redux
 
Curator intro
Curator introCurator intro
Curator intro
 
Road to react hooks
Road to react hooksRoad to react hooks
Road to react hooks
 
Matteo Collina | Take your HTTP server to Ludicrous Speed | Codmeotion Madrid...
Matteo Collina | Take your HTTP server to Ludicrous Speed | Codmeotion Madrid...Matteo Collina | Take your HTTP server to Ludicrous Speed | Codmeotion Madrid...
Matteo Collina | Take your HTTP server to Ludicrous Speed | Codmeotion Madrid...
 
Asyc flow control with javascript generators - redux-saga
Asyc flow control with javascript generators - redux-sagaAsyc flow control with javascript generators - redux-saga
Asyc flow control with javascript generators - redux-saga
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Jdk 7 4-forkjoin
Jdk 7 4-forkjoinJdk 7 4-forkjoin
Jdk 7 4-forkjoin
 
Recompacting your react application
Recompacting your react applicationRecompacting your react application
Recompacting your react application
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applications
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
What's new in WorkManager-Andri Suranta Ginting (Product Engineer-Gojek)
What's new in WorkManager-Andri Suranta Ginting (Product Engineer-Gojek)What's new in WorkManager-Andri Suranta Ginting (Product Engineer-Gojek)
What's new in WorkManager-Andri Suranta Ginting (Product Engineer-Gojek)
 
Douglas Crockford: Serversideness
Douglas Crockford: ServersidenessDouglas Crockford: Serversideness
Douglas Crockford: Serversideness
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
 
Redux Deep Dive - ReactFoo Pune 2018
Redux Deep Dive - ReactFoo Pune 2018Redux Deep Dive - ReactFoo Pune 2018
Redux Deep Dive - ReactFoo Pune 2018
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at Pinterest
 
Android Loaders : Reloaded
Android Loaders : ReloadedAndroid Loaders : Reloaded
Android Loaders : Reloaded
 
React. Redux. Real world.
React. Redux. Real world.React. Redux. Real world.
React. Redux. Real world.
 
Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)
Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)
Amazing threesome, rrr... React. Redux. Real world / Ростислав Галкин (Babo)
 
Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
 

More from GlobalLogic Ukraine

GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”GlobalLogic Ukraine
 
Штучний інтелект як допомога в навчанні, а не замінник.pptx
Штучний інтелект як допомога в навчанні, а не замінник.pptxШтучний інтелект як допомога в навчанні, а не замінник.pptx
Штучний інтелект як допомога в навчанні, а не замінник.pptxGlobalLogic Ukraine
 
Задачі AI-розробника як застосовується штучний інтелект.pptx
Задачі AI-розробника як застосовується штучний інтелект.pptxЗадачі AI-розробника як застосовується штучний інтелект.pptx
Задачі AI-розробника як застосовується штучний інтелект.pptxGlobalLogic Ukraine
 
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptxЩо треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptxGlobalLogic Ukraine
 
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...GlobalLogic Ukraine
 
JavaScript Community Webinar #14 "Why Is Git Rebase?"
JavaScript Community Webinar #14 "Why Is Git Rebase?"JavaScript Community Webinar #14 "Why Is Git Rebase?"
JavaScript Community Webinar #14 "Why Is Git Rebase?"GlobalLogic Ukraine
 
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...GlobalLogic Ukraine
 
Страх і сила помилок - IT Inside від GlobalLogic Education
Страх і сила помилок - IT Inside від GlobalLogic EducationСтрах і сила помилок - IT Inside від GlobalLogic Education
Страх і сила помилок - IT Inside від GlobalLogic EducationGlobalLogic Ukraine
 
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”GlobalLogic Ukraine
 
GlobalLogic QA Webinar “What does it take to become a Test Engineer”
GlobalLogic QA Webinar “What does it take to become a Test Engineer”GlobalLogic QA Webinar “What does it take to become a Test Engineer”
GlobalLogic QA Webinar “What does it take to become a Test Engineer”GlobalLogic Ukraine
 
“How to Secure Your Applications With a Keycloak?
“How to Secure Your Applications With a Keycloak?“How to Secure Your Applications With a Keycloak?
“How to Secure Your Applications With a Keycloak?GlobalLogic Ukraine
 
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...GlobalLogic Ukraine
 
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...GlobalLogic Ukraine
 
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”GlobalLogic Ukraine
 
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"GlobalLogic Ukraine
 
GlobalLogic Webinar "Introduction to Embedded QA"
GlobalLogic Webinar "Introduction to Embedded QA"GlobalLogic Webinar "Introduction to Embedded QA"
GlobalLogic Webinar "Introduction to Embedded QA"GlobalLogic Ukraine
 
C++ Webinar "Why Should You Learn C++ in 2021-22?"
C++ Webinar "Why Should You Learn C++ in 2021-22?"C++ Webinar "Why Should You Learn C++ in 2021-22?"
C++ Webinar "Why Should You Learn C++ in 2021-22?"GlobalLogic Ukraine
 
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...GlobalLogic Ukraine
 
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...GlobalLogic Ukraine
 
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”GlobalLogic Ukraine
 

More from GlobalLogic Ukraine (20)

GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
 
Штучний інтелект як допомога в навчанні, а не замінник.pptx
Штучний інтелект як допомога в навчанні, а не замінник.pptxШтучний інтелект як допомога в навчанні, а не замінник.pptx
Штучний інтелект як допомога в навчанні, а не замінник.pptx
 
Задачі AI-розробника як застосовується штучний інтелект.pptx
Задачі AI-розробника як застосовується штучний інтелект.pptxЗадачі AI-розробника як застосовується штучний інтелект.pptx
Задачі AI-розробника як застосовується штучний інтелект.pptx
 
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptxЩо треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
 
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
 
JavaScript Community Webinar #14 "Why Is Git Rebase?"
JavaScript Community Webinar #14 "Why Is Git Rebase?"JavaScript Community Webinar #14 "Why Is Git Rebase?"
JavaScript Community Webinar #14 "Why Is Git Rebase?"
 
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
 
Страх і сила помилок - IT Inside від GlobalLogic Education
Страх і сила помилок - IT Inside від GlobalLogic EducationСтрах і сила помилок - IT Inside від GlobalLogic Education
Страх і сила помилок - IT Inside від GlobalLogic Education
 
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
 
GlobalLogic QA Webinar “What does it take to become a Test Engineer”
GlobalLogic QA Webinar “What does it take to become a Test Engineer”GlobalLogic QA Webinar “What does it take to become a Test Engineer”
GlobalLogic QA Webinar “What does it take to become a Test Engineer”
 
“How to Secure Your Applications With a Keycloak?
“How to Secure Your Applications With a Keycloak?“How to Secure Your Applications With a Keycloak?
“How to Secure Your Applications With a Keycloak?
 
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
 
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
 
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
 
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
 
GlobalLogic Webinar "Introduction to Embedded QA"
GlobalLogic Webinar "Introduction to Embedded QA"GlobalLogic Webinar "Introduction to Embedded QA"
GlobalLogic Webinar "Introduction to Embedded QA"
 
C++ Webinar "Why Should You Learn C++ in 2021-22?"
C++ Webinar "Why Should You Learn C++ in 2021-22?"C++ Webinar "Why Should You Learn C++ in 2021-22?"
C++ Webinar "Why Should You Learn C++ in 2021-22?"
 
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...
GlobalLogic Test Automation Live Testing Session “Android Behind UI — Testing...
 
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
GlobalLogic Test Automation Online TechTalk “Test Driven Development as a Per...
 
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”
GlobalLogic Azure TechTalk ONLINE “Marketing Data Lake in Azure”
 

Recently uploaded

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 

Recently uploaded (20)

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 

Using Redux-Saga for Handling Side Effects

  • 1. 1 Using Redux-Saga for Handling Side Effects Igor Nesterenko Lead Software Engineer 17.08.2018
  • 2. 2 Agenda 1. Problem 2. Solutions 3. redux-saga 4. Basic Concepts 5. Advanced Concepts 6. Unit Testing 7. Recommendations 8. Loose Coupled System 9. Summary 10.Future Reading
  • 4. 4 Problem 1. Side-effects are roots of errors and mistrust • Async (aka concurrency) is hard 2. A program without side effects is useless 3. React and redux don’t solve that all issue
  • 6. 6 Solutions 1. Custom redux middleware 2. redux-thunk (action creator) 3. redux-saga (saga) 4. redux-loop (reducer)
  • 8. 8 redux-saga 1. Origins of Saga Pattern 2. The Process Manager Pattern 3. redux-saga
  • 10. 10 Origins of Saga Pattern Saga is a failure management pattern ● T - transaction ● C - compensation action
  • 12. 12 The Process Manager Sagas ES6 generators Saga Monitor redux middleware Redux Action
  • 13. 13 Confusions around saga pattern 1. Saga is a failure management pattern 2. redux-saga is an alternative side effect model for Redux apps
  • 15. 15 Terms 1. Effect - is a single, atomic predefined instruction or command (POJO) 2. Saga - collection of effects, realized in form of ES6 generator 3. Saga Middleware - redux middleware to execute sagas 4. Effect Creator - function to create effect objects 5. Channels - queues for actions 6. Helper and Untils - helper functions for day to day tasks, factory function to wrap external IO or event channels
  • 16. 16 Effect and Effect Creator put({type: 'INCREMENT'}) // => { PUT: {type: 'INCREMENT'} } call(delay, 1000) // => { CALL: {fn: delay, args: [1000]}}
  • 17. 17 Effect Creators ● take ● put ● call, apply ● fork, spawn ● cancel, canceled ● select
  • 18. 18 Saga Example // Our worker Saga: will perform the async increment task export function* incrementAsync() { yield delay(1000) yield put({ type: 'INCREMENT' }) }
  • 19. 19 Setup Saga const sagaMiddleware = createSagaMiddleware() const store = createStore( reducer, applyMiddleware(sagaMiddleware) ) sagaMiddleware.run(helloSaga) const action = type => store.dispatch({type})
  • 20. 20 Synchronous Like Code function* fetchProducts() { try { const products = yield call(Api.fetch, '/products') yield put({ type: 'PRODUCTS_RECEIVED', products }) } catch(error) { yield put({ type: 'PRODUCTS_REQUEST_FAILED', error }) } finally { if (yield cancelled()) yield put({ type: 'PRODUCTS_REQUEST_FAILED', new Error('Canceled')}) } }
  • 21. 21 Pull Future Action function* loginFlow() { while (true) { yield take('LOGIN') // ... perform the login logic yield take('LOGOUT') // ... perform the logout logic } }
  • 23. 23 Advanced Concepts 1. Helper utils 2. Effect Combinators 3. Fork Model 4. Channels 5. External I/O
  • 24. 24 Helper Utils and Effect Creators export default function* rootSaga() { yield takeLatest('FETCH_USERS', fetchUsers) yield takeEvery('CREATE_USER', createUser) }
  • 25. 25 Effect Combinators ● Run Tasks in Parallel ● Starting Race Between Multiple Tasks
  • 26. 26 Effect Combinators - all function* fetchAll() { yield all([ call(fetchResource, 'users'), // task1 call(fetchResource, 'comments'), // task2, call(delay, 1000) ]) }
  • 27. 27 Effect Combinators - race function* fetchPostsWithTimeout() { const {posts, timeout} = yield race({ posts: call(fetchApi, '/posts'), timeout: call(delay, 1000) }) if (posts) put({type: 'POSTS_RECEIVED', posts}) else put({type: 'TIMEOUT_ERROR'}) }
  • 28. 28 Effect Combinators - Not Only For Requests function* backgroundTask() { while (true) { ... } } function* watchStartBackgroundTask() { while (true) { yield take('START_BACKGROUND_TASK') yield race({ task: call(backgroundTask), cancel: take('CANCEL_TASK') }) } }
  • 29. 29 Fork Model ● fork is used to create attached fork ● spawn is used to create detached forks ● non-blocking
  • 30. 30 Fork Model Fetch All Fetch Comments Fetch Users main Blocking Call Non-blocking Call Wait All for Terminate
  • 31. 31 Fork Model - Completion function* fetchAll() { const task1 = yield fork(fetchResource, 'users') const task2 = yield fork(fetchResource, 'comments') yield call(delay, 1000) } function* main() { yield call(fetchAll) } Non-blocking Blocking
  • 32. 32 Fork Model - Error PropagationFork Model Fetch All Fetch Comments Fetch Users main Blocking Call Non-blocking Call Catch All Errors Catch Forks Errors
  • 33. 33 Fork Model - Error Propagation try{ yield fork(watchBgTask); yield fork(watchCheckout) } catch (err) { yield put({type:”CRITICAL_ERROR”}); }
  • 34. 34 Fork Model - Cancelation function* main() { while ( yield take(START_BACKGROUND_SYNC) ) { const bgSyncTask = yield fork(bgSync) yield take(STOP_BACKGROUND_SYNC) yield cancel(bgSyncTask) } }
  • 35. 35 Fork Model - Detect Cancellation Inside Saga function* bgSync() { try { while (true) { yield put(actions.requestStart()) const result = yield call(someApi) yield put(actions.requestSuccess(result)) } } finally { if (yield cancelled()) yield put(actions.requestFailure('Sync cancelled!')) } }
  • 36. 36 Channels ● Buffer actions from the Redux Store ● Connect take effect to external event source ● Communicate between sagas
  • 37. 37 Channels - Buffer Actions Saga F1 Fork F2 F3 Store Put 1 Request 1 Request 2 Request 3 Take Put 2 Put 3
  • 38. 38 Channels - Buffer Actions function* watchRequests() { while (true) { const {payload} = yield take('REQUEST') yield fork(handleRequest, payload) } }
  • 39. 39 Channels - Buffer Actions Saga StorePut 2 Request 1 Request 2 Request 3 Channel Put 1 Put 3 Store in Buffer
  • 40. 40 Channels - Buffer Actions function* watchRequests() { const requestChan = yield actionChannel('REQUEST') while (true) { const {payload} = yield take(requestChan) yield call(handleRequest, payload) } }
  • 41. 41 Channels - Buffer Actions function* watchRequests() { const requestChan = yield actionChannel('REQUEST') while (true) { const {payload} = yield take(requestChan) yield call(handleRequest, payload) } }
  • 42. 42 Channels - eventChannel Socket Channel Saga ChanneleventChannel as argument creates My Saga take, put● emmiter(payload) ● emmiter(END)
  • 43. 43 Channels - eventChannel export function* watchOnPings() { const socket = yield call(createWebSocketConnection) const socketChannel = yield call(createSocketChannel, socket) while (true) { const payload = yield take(socketChannel) yield put({ type: INCOMING_PONG_PAYLOAD, payload }) yield fork(pong, socket) } }
  • 44. 44 Channels - eventChannel function* pong(socket) { yield call(delay, 5000) yield apply(socket, socket.emit, ['pong']) }
  • 45. 45 Channels - Communication Between Sagas Fork 1 Fork 2 Fork 3 Saga Shared Channel aka load balancing Push message to free fork create
  • 46. 46 Channels - Communication Between Sagas function* watchRequests() { const chan = yield call(channel) for (var i = 0; i < 3; i++) { yield fork(handleRequest, chan) } while (true) { const {payload} = yield take('REQUEST') yield put(chan, payload) } }
  • 47. 47 Channels - Communication Between Sagas function* handleRequest(chan) { while (true) { const payload = yield take(chan) // process the request } }
  • 49. 49 Unit Testing ● Mockless unit testing ● Saga Helpers
  • 50. 50 Unit Testing - Iterate and Compare function* incrementAsync() { yield delay(1000) yield put({ type: 'INCREMENT' }) }
  • 51. 51 Unit Testing - Iterate and Compare test('incrementAsync Saga test', (assert) => { const gen = incrementAsync() // now what ? });
  • 52. 52 Unit Testing - Iterate and Compare gen.next() //=>{ done: false, value: <result ... delay(1000)> } gen.next() //=>{ done: false, value: <result ... put({...})> } gen.next() //=>{ done: true, value: undefined }
  • 53. 53 Unit Testing - Iterate and Compare test('incrementAsync Saga test', (assert) => { const gen = incrementAsync() assert.deepEqual( gen.next().value, call(delay, 1000), 'incrementAsync Saga must call delay(1000)' ) // .... });
  • 54. 54 Unit Testing - Different Branches function* doStuffThenChangeColor() { yield put(doStuff()); yield put(doStuff()); const action = yield take(CHOOSE_NUMBER); if (action.payload.number % 2 === 0) { yield put(changeUI('red')); } else { yield put(changeUI('blue')); } }
  • 55. 55 Unit Testing - Clonable Generator test('doStuffThenChangeColor', assert => { const gen = cloneableGenerator(doStuffThenChangeColor)(); gen.next(); // DO_STUFF gen.next(); // DO_STUFF gen.next(); // CHOOSE_NUMBER // ... });
  • 56. 56 Unit Testing - Clonable Generator - First Branch const gen = cloneableGenerator(doStuffThenChangeColor)(); // ... const clone = gen.clone(); assert.deepEqual( clone.next(chooseNumber(2)).value, put(changeUI('red')), 'should change the color to red' );
  • 57. 57 Unit Testing - Clonable Generator - Second Branch const gen = cloneableGenerator(doStuffThenChangeColor)(); // ... const otherClone = gen.clone(); assert.deepEqual( otherClone.next(chooseNumber(3)).value, put(changeUI('blue')), 'should change the color to blue' );
  • 58. 58 Unit Testing - Clonable Generator test('doStuffThenChangeColor', assert => { const gen = cloneableGenerator(doStuffThenChangeColor)(); gen.next(); // DO_STUFF gen.next(); // DO_STUFF gen.next(); // CHOOSE_NUMBER // ... });
  • 59. 59 Unit Testing - Fork Effect function* main() { while ( yield take(START_BACKGROUND_SYNC) ) { const bgSyncTask = yield fork(bgSync) yield take(STOP_BACKGROUND_SYNC) yield cancel(bgSyncTask) } }
  • 60. 60 Unit Testing - Fork Effect expect(generator.next().value).toEqual(take(START_BG_SYNC)); expect(generator.next({ type: 'START_BG_SYNC' }).value).toEqual(fork(bgSync)); const mockTask = createMockTask(); expect(generator.next(mockTask).value).toEqual(take(STOP_BACKGROUND_SYNC)); expect(generator.next().value).toEqual(cancel(mockTask));
  • 62. 62 Recommendations 1. Code Smells 2. Integration with React Component 3. Identify Core Flows 4. Invest in error-handling 5. Extract Reusable Saga 6. Unit Testing strategy
  • 64. 64 Code Smells - Routing in Sagas // ... import { push } from 'react-router-redux'; export default function* handleProductRedirect() { const productId = yield select(getRouterProductId); yield put(push(`/checkout/product/${productId}`)); }
  • 65. 65 Code Smells - Reducer Logic in Sagas export function* watchForSomething() { while (true) { const {payload: {oneThing, anotherThing}} = yield take(SOME_THING); yield put(DO_ONE_THING, oneThing); yield put(DO_ANOTHER_THING, anotherThing); } }
  • 66. 66 Code Smells - Reducer Logic in Sagas ● Data Massaging ● switch for action.type ... ● Something other then Side-Effect
  • 67. 67 Extract Reusable Saga export default function standartRequest(request, success, failure) { return function* requestHandlingSaga(action) { try { const response = yield call(request, action.payload); yield put(success(response)); } catch (error) { yield put(failure(error)); } }; }
  • 68. 68 Extract Reusable Saga const handleEntityRequest = standartRequest( Api.fetchEntity ENTITY_REQUEST_SUCCESS, ENTITY_REQUEST_ERROR )
  • 69. 69 Integration with React Component ● componentDidMount - initialize sub-flow ● componentWillUnmount - teardown sub-flow ● Combine with Routing ● Sync with bootstrap of application
  • 70. 70 Combine With Routing • /entities/ -> EntitiesRoute - dispatch list request • /entities/ -> EntitiesList • /entities/:id -> EntityRoute - dispatch single entity ●/entities/:id -> Entity ●/entities/:id/edit -> EntityEdit - dispatch save
  • 71. 71 Combine With Routing export default function* watchEntities() { yield takeLatest(ENTITES_REQUEST,handleEntitiesRequest); yield takeLatest(ENTITY_REQUEST,handleEntityRequest); yield takeLatest(ENTITY_SAVE_REQUEST,handleEntitySaveRequest); }
  • 72. 72 Sync with Application Bootstrap export default function* watchEntities() { yield takeLatest(ENTITES_REQUEST, runAfterAuth(handleEntitysRequest)), yield takeLatest(ENTITY_REQUEST, runAfterAuth(handleEntityRequest)); yield takeLatest(ENTITY_SAVE_REQUEST, handleEntitySaveRequest); }
  • 73. 73 Sync with Application Bootstrap export default function* runAfterAuth(handler) { return function* (action){ const isAuthenticated = yield select(isAppAuthDone); if (!isAuthenticated) { yield take(APP_AUTH_SUCCESS); } yield call(handler, action) } }
  • 74. 74 Invest in Error Handling 1. Acton Error Naming Convention • like “*_ERROR” postfix in actions naming 2. Unified way to make requests, I/O 3. Logger and some UI to show error to the user
  • 75. 75 Error Handling export default function* rootSaga() { try { yield all([ watchAuth(), watchEntities() ]) } catch (e) { logger.error(e); yield put(errorCritical(e)); } }
  • 78. 78 Unit Testing Strategy 1. Start from covering top flows for example • must have watchAuth, watchCheckout • nice to have watchEntities 2. Cover reusable sagas like standartRequest, runAfterAuth
  • 82. 82 Summary 1. Inspired by Saga pattern, however it’s not exact implementation of Saga pattern 2. Provides constraints to handle side-effects in one place 3. Allows maintainable unit testing of side-effect (without mocking) 4. Saga works great for side-effects, but produces code smells if used for other tasks like routing, data massaging (aka reducers logic)
  • 84. 84 Future Reading ● Origins ○ Sagas - original paper ○ Confusion about Saga pattern ○ Clarifying the Saga pattern ○ Communicating Sequential Processes ● redux-saga ○ Saga ? Why not CSP ? ○ External Resources ● Other Domains ○ Applying Saga Pattern ○ Sagas ● Unit Testing ○ Mocking is a Code Smell
  • 88. 88 Side-Effects ● State/Assignments ● Read/Write Data ● Communicate Over Network ● Raise Exception ● DOM In computer science, a function or expression is said to have a side effect if, in addition to producing a value, it also modifies some state or has an observable interaction with calling functions or the outside world
  • 89. 89 Give Me a Label const label = await this.getLabel();
  • 90. 90 May Launch Missiles async function getLabel () { const val = Math.random(); if (val > 0.5){ await launchMissles(); return `foo foo ${val}` } return `blah blah ${val}`; }
  • 91. 91 Why should I care about side effects ? “Side effects are lies. Your function promises to do one thing, but it also does other hidden things...they are devious and damaging mistruths that often result in strange temporal couplings and order dependencies.” Clean Code, Robert Martin
  • 92. 92 Things to remember ● A program without side effects is useless ● Side effects are neither evil nor taboo ● The key is to ○ limit side effects ○ clearly identify them ○ avoid scattering them throughout the code.
  • 93. 93 Minuses ● issues with stacktrace ● more boilerplate code ● structuring sagas ● learning curve
  • 94. 94 Pluses ● side-effects isolated in one place ● maintainable code (unit testable) ● loosely coupled system
  • 96. 96 Basics Concepts 1. Separate Instructions from Execution 2. Use ES6 generator to define set of instructions 3. Use redux middleware to execute instructions 4. Execution works with `pull-future-actions` approach
  • 97. 97 Saga 1. Improve Loose Coupling (SR, Component and Actions) 2. Something on top of async/await, Observables 3. Maintainable Unit Testing (without mocks) 4. Makes important business flows explicitly defined in code 5. More explicit error handling techniques