Saga always cancelled











up vote
1
down vote

favorite












I use redux-saga and have the following code:



function* loginFlow(username, password) {
try {
yield call(loginApi, username, password);
yield put({ type: LOGIN_SUCCESS });
yield put({ type: TOGGLE_LOGGED_DONE, payload: true });
yield put(push('/dashboard'));
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
} finally {
if (yield cancelled()) {
console.log('ALWAYS CANCELLED');
// yield put(replace('/login'));
}
}
}

// Watcher saga.
function* loginWatcher() {
while (true) {
const { username, password } = yield take(LOGIN_REQUESTING);
const task = yield fork(loginFlow, username, password);
const action = yield take([LOGOUT, LOGIN_ERROR]);
if (action.type === LOGOUT) yield cancel(task);
yield call(logoutUser);
}
}


The problem is that the loginFlow function always get cancelled in the end (I see 'ALWAYS CANCELLED' in console). Even if I remove const action = yield take([LOGOUT, LOGIN_ERROR]); and yield call(logoutUser); from loginWatcher.



I can't see that either LOGOUT or LOGIN_ERROR are fired:
Redux devtools output



Any ideas what wrong with my code?



Note that I use withRouter in the index.js for login page where saga above is (else I get blank screen when redirect):



const withSaga = injectSaga({ key: 'login', saga }); 

export default compose( withReducer, withSaga, withConnect, )(LoginPage);


Best Regards



EDIT:
If wrapping loginWatcher in try/catch I also go to finally there:



function* loginWatcher() {
while (true) {
try {
const { username, password } = yield take(LOGIN_REQUESTING);
const task = yield fork(loginFlow, username, password);
const action = yield take([LOGOUT, LOGIN_ERROR]);
if (action.type === LOGOUT) yield cancel(task);
yield call(logoutUser);
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
} finally {
if (yield cancelled()) {
console.log('HERE AS WELL');
// yield put(push('/login'));
}
}
}
}









share|improve this question
























  • Wrap loginWatcher() in a try { ... } finally { if (yield cancelled()) { ... } }. I suspect it gets cancelled too.
    – Andrey Moiseev
    Nov 9 at 13:46










  • @AndreyMoiseev Did you mean like my edit? Go to finally there as well with try/catch...
    – user1665355
    Nov 9 at 14:28










  • @AndreyMoiseev Seems to be something with yield cancelled(), it's always true...
    – user1665355
    Nov 9 at 14:29










  • In redux-saga, all forked and called sagas are cancelled recursively. Something in your code is cancelling loginWatcher(), which in its turn recursively cancels loginFlow(). I suspect two things: 1) the code where you start loginWatcher() cancels it, 2) yield put(push('/dashboard')) cases a side effect somewhere in your code, and cancels it.
    – Andrey Moiseev
    Nov 9 at 14:55










  • Please add the code where you start loginWatcher(), and the code where you handle LOCATION_CHANGE. Also, check out this question. Probably you have code that cancels sagas on LOCATION_CHANGE.
    – Andrey Moiseev
    Nov 9 at 14:58















up vote
1
down vote

favorite












I use redux-saga and have the following code:



function* loginFlow(username, password) {
try {
yield call(loginApi, username, password);
yield put({ type: LOGIN_SUCCESS });
yield put({ type: TOGGLE_LOGGED_DONE, payload: true });
yield put(push('/dashboard'));
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
} finally {
if (yield cancelled()) {
console.log('ALWAYS CANCELLED');
// yield put(replace('/login'));
}
}
}

// Watcher saga.
function* loginWatcher() {
while (true) {
const { username, password } = yield take(LOGIN_REQUESTING);
const task = yield fork(loginFlow, username, password);
const action = yield take([LOGOUT, LOGIN_ERROR]);
if (action.type === LOGOUT) yield cancel(task);
yield call(logoutUser);
}
}


The problem is that the loginFlow function always get cancelled in the end (I see 'ALWAYS CANCELLED' in console). Even if I remove const action = yield take([LOGOUT, LOGIN_ERROR]); and yield call(logoutUser); from loginWatcher.



I can't see that either LOGOUT or LOGIN_ERROR are fired:
Redux devtools output



Any ideas what wrong with my code?



Note that I use withRouter in the index.js for login page where saga above is (else I get blank screen when redirect):



const withSaga = injectSaga({ key: 'login', saga }); 

export default compose( withReducer, withSaga, withConnect, )(LoginPage);


Best Regards



EDIT:
If wrapping loginWatcher in try/catch I also go to finally there:



function* loginWatcher() {
while (true) {
try {
const { username, password } = yield take(LOGIN_REQUESTING);
const task = yield fork(loginFlow, username, password);
const action = yield take([LOGOUT, LOGIN_ERROR]);
if (action.type === LOGOUT) yield cancel(task);
yield call(logoutUser);
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
} finally {
if (yield cancelled()) {
console.log('HERE AS WELL');
// yield put(push('/login'));
}
}
}
}









share|improve this question
























  • Wrap loginWatcher() in a try { ... } finally { if (yield cancelled()) { ... } }. I suspect it gets cancelled too.
    – Andrey Moiseev
    Nov 9 at 13:46










  • @AndreyMoiseev Did you mean like my edit? Go to finally there as well with try/catch...
    – user1665355
    Nov 9 at 14:28










  • @AndreyMoiseev Seems to be something with yield cancelled(), it's always true...
    – user1665355
    Nov 9 at 14:29










  • In redux-saga, all forked and called sagas are cancelled recursively. Something in your code is cancelling loginWatcher(), which in its turn recursively cancels loginFlow(). I suspect two things: 1) the code where you start loginWatcher() cancels it, 2) yield put(push('/dashboard')) cases a side effect somewhere in your code, and cancels it.
    – Andrey Moiseev
    Nov 9 at 14:55










  • Please add the code where you start loginWatcher(), and the code where you handle LOCATION_CHANGE. Also, check out this question. Probably you have code that cancels sagas on LOCATION_CHANGE.
    – Andrey Moiseev
    Nov 9 at 14:58













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I use redux-saga and have the following code:



function* loginFlow(username, password) {
try {
yield call(loginApi, username, password);
yield put({ type: LOGIN_SUCCESS });
yield put({ type: TOGGLE_LOGGED_DONE, payload: true });
yield put(push('/dashboard'));
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
} finally {
if (yield cancelled()) {
console.log('ALWAYS CANCELLED');
// yield put(replace('/login'));
}
}
}

// Watcher saga.
function* loginWatcher() {
while (true) {
const { username, password } = yield take(LOGIN_REQUESTING);
const task = yield fork(loginFlow, username, password);
const action = yield take([LOGOUT, LOGIN_ERROR]);
if (action.type === LOGOUT) yield cancel(task);
yield call(logoutUser);
}
}


The problem is that the loginFlow function always get cancelled in the end (I see 'ALWAYS CANCELLED' in console). Even if I remove const action = yield take([LOGOUT, LOGIN_ERROR]); and yield call(logoutUser); from loginWatcher.



I can't see that either LOGOUT or LOGIN_ERROR are fired:
Redux devtools output



Any ideas what wrong with my code?



Note that I use withRouter in the index.js for login page where saga above is (else I get blank screen when redirect):



const withSaga = injectSaga({ key: 'login', saga }); 

export default compose( withReducer, withSaga, withConnect, )(LoginPage);


Best Regards



EDIT:
If wrapping loginWatcher in try/catch I also go to finally there:



function* loginWatcher() {
while (true) {
try {
const { username, password } = yield take(LOGIN_REQUESTING);
const task = yield fork(loginFlow, username, password);
const action = yield take([LOGOUT, LOGIN_ERROR]);
if (action.type === LOGOUT) yield cancel(task);
yield call(logoutUser);
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
} finally {
if (yield cancelled()) {
console.log('HERE AS WELL');
// yield put(push('/login'));
}
}
}
}









share|improve this question















I use redux-saga and have the following code:



function* loginFlow(username, password) {
try {
yield call(loginApi, username, password);
yield put({ type: LOGIN_SUCCESS });
yield put({ type: TOGGLE_LOGGED_DONE, payload: true });
yield put(push('/dashboard'));
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
} finally {
if (yield cancelled()) {
console.log('ALWAYS CANCELLED');
// yield put(replace('/login'));
}
}
}

// Watcher saga.
function* loginWatcher() {
while (true) {
const { username, password } = yield take(LOGIN_REQUESTING);
const task = yield fork(loginFlow, username, password);
const action = yield take([LOGOUT, LOGIN_ERROR]);
if (action.type === LOGOUT) yield cancel(task);
yield call(logoutUser);
}
}


The problem is that the loginFlow function always get cancelled in the end (I see 'ALWAYS CANCELLED' in console). Even if I remove const action = yield take([LOGOUT, LOGIN_ERROR]); and yield call(logoutUser); from loginWatcher.



I can't see that either LOGOUT or LOGIN_ERROR are fired:
Redux devtools output



Any ideas what wrong with my code?



Note that I use withRouter in the index.js for login page where saga above is (else I get blank screen when redirect):



const withSaga = injectSaga({ key: 'login', saga }); 

export default compose( withReducer, withSaga, withConnect, )(LoginPage);


Best Regards



EDIT:
If wrapping loginWatcher in try/catch I also go to finally there:



function* loginWatcher() {
while (true) {
try {
const { username, password } = yield take(LOGIN_REQUESTING);
const task = yield fork(loginFlow, username, password);
const action = yield take([LOGOUT, LOGIN_ERROR]);
if (action.type === LOGOUT) yield cancel(task);
yield call(logoutUser);
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
} finally {
if (yield cancelled()) {
console.log('HERE AS WELL');
// yield put(push('/login'));
}
}
}
}






redux-saga






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 9 at 15:30

























asked Nov 9 at 10:27









user1665355

99652350




99652350












  • Wrap loginWatcher() in a try { ... } finally { if (yield cancelled()) { ... } }. I suspect it gets cancelled too.
    – Andrey Moiseev
    Nov 9 at 13:46










  • @AndreyMoiseev Did you mean like my edit? Go to finally there as well with try/catch...
    – user1665355
    Nov 9 at 14:28










  • @AndreyMoiseev Seems to be something with yield cancelled(), it's always true...
    – user1665355
    Nov 9 at 14:29










  • In redux-saga, all forked and called sagas are cancelled recursively. Something in your code is cancelling loginWatcher(), which in its turn recursively cancels loginFlow(). I suspect two things: 1) the code where you start loginWatcher() cancels it, 2) yield put(push('/dashboard')) cases a side effect somewhere in your code, and cancels it.
    – Andrey Moiseev
    Nov 9 at 14:55










  • Please add the code where you start loginWatcher(), and the code where you handle LOCATION_CHANGE. Also, check out this question. Probably you have code that cancels sagas on LOCATION_CHANGE.
    – Andrey Moiseev
    Nov 9 at 14:58


















  • Wrap loginWatcher() in a try { ... } finally { if (yield cancelled()) { ... } }. I suspect it gets cancelled too.
    – Andrey Moiseev
    Nov 9 at 13:46










  • @AndreyMoiseev Did you mean like my edit? Go to finally there as well with try/catch...
    – user1665355
    Nov 9 at 14:28










  • @AndreyMoiseev Seems to be something with yield cancelled(), it's always true...
    – user1665355
    Nov 9 at 14:29










  • In redux-saga, all forked and called sagas are cancelled recursively. Something in your code is cancelling loginWatcher(), which in its turn recursively cancels loginFlow(). I suspect two things: 1) the code where you start loginWatcher() cancels it, 2) yield put(push('/dashboard')) cases a side effect somewhere in your code, and cancels it.
    – Andrey Moiseev
    Nov 9 at 14:55










  • Please add the code where you start loginWatcher(), and the code where you handle LOCATION_CHANGE. Also, check out this question. Probably you have code that cancels sagas on LOCATION_CHANGE.
    – Andrey Moiseev
    Nov 9 at 14:58
















Wrap loginWatcher() in a try { ... } finally { if (yield cancelled()) { ... } }. I suspect it gets cancelled too.
– Andrey Moiseev
Nov 9 at 13:46




Wrap loginWatcher() in a try { ... } finally { if (yield cancelled()) { ... } }. I suspect it gets cancelled too.
– Andrey Moiseev
Nov 9 at 13:46












@AndreyMoiseev Did you mean like my edit? Go to finally there as well with try/catch...
– user1665355
Nov 9 at 14:28




@AndreyMoiseev Did you mean like my edit? Go to finally there as well with try/catch...
– user1665355
Nov 9 at 14:28












@AndreyMoiseev Seems to be something with yield cancelled(), it's always true...
– user1665355
Nov 9 at 14:29




@AndreyMoiseev Seems to be something with yield cancelled(), it's always true...
– user1665355
Nov 9 at 14:29












In redux-saga, all forked and called sagas are cancelled recursively. Something in your code is cancelling loginWatcher(), which in its turn recursively cancels loginFlow(). I suspect two things: 1) the code where you start loginWatcher() cancels it, 2) yield put(push('/dashboard')) cases a side effect somewhere in your code, and cancels it.
– Andrey Moiseev
Nov 9 at 14:55




In redux-saga, all forked and called sagas are cancelled recursively. Something in your code is cancelling loginWatcher(), which in its turn recursively cancels loginFlow(). I suspect two things: 1) the code where you start loginWatcher() cancels it, 2) yield put(push('/dashboard')) cases a side effect somewhere in your code, and cancels it.
– Andrey Moiseev
Nov 9 at 14:55












Please add the code where you start loginWatcher(), and the code where you handle LOCATION_CHANGE. Also, check out this question. Probably you have code that cancels sagas on LOCATION_CHANGE.
– Andrey Moiseev
Nov 9 at 14:58




Please add the code where you start loginWatcher(), and the code where you handle LOCATION_CHANGE. Also, check out this question. Probably you have code that cancels sagas on LOCATION_CHANGE.
– Andrey Moiseev
Nov 9 at 14:58












1 Answer
1






active

oldest

votes

















up vote
1
down vote



accepted










I'm posting what we've gathered as an answer, so that this question is useful for future readers.



In redux-saga, sagas started via call() and fork() are cancelled recursively. Saga means a recursively cancellable task. So when a saga gets cancelled, you should check its parent saga, and so on.



This code snippet you've posted:



const withSaga = injectSaga({ key: 'login', saga });
export default compose( withReducer, withSaga, withConnect, )(LoginPage)


Google suggests that it uses this redux-saga + react-boilerplate example. It covers cancellation and how to disable it. Check the link to find out about it.



I'm not familiar with react-boilerplate (React ecosystem is huge), but I guess my answer at least narrows down the search. Consider asking a separate question with react-boilerplate if you get confused.






share|improve this answer





















  • Thank you! What works is to move saga to global scope. Then it is not cancelled during route change!
    – user1665355
    Nov 10 at 15:43











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53223958%2fsaga-always-cancelled%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote



accepted










I'm posting what we've gathered as an answer, so that this question is useful for future readers.



In redux-saga, sagas started via call() and fork() are cancelled recursively. Saga means a recursively cancellable task. So when a saga gets cancelled, you should check its parent saga, and so on.



This code snippet you've posted:



const withSaga = injectSaga({ key: 'login', saga });
export default compose( withReducer, withSaga, withConnect, )(LoginPage)


Google suggests that it uses this redux-saga + react-boilerplate example. It covers cancellation and how to disable it. Check the link to find out about it.



I'm not familiar with react-boilerplate (React ecosystem is huge), but I guess my answer at least narrows down the search. Consider asking a separate question with react-boilerplate if you get confused.






share|improve this answer





















  • Thank you! What works is to move saga to global scope. Then it is not cancelled during route change!
    – user1665355
    Nov 10 at 15:43















up vote
1
down vote



accepted










I'm posting what we've gathered as an answer, so that this question is useful for future readers.



In redux-saga, sagas started via call() and fork() are cancelled recursively. Saga means a recursively cancellable task. So when a saga gets cancelled, you should check its parent saga, and so on.



This code snippet you've posted:



const withSaga = injectSaga({ key: 'login', saga });
export default compose( withReducer, withSaga, withConnect, )(LoginPage)


Google suggests that it uses this redux-saga + react-boilerplate example. It covers cancellation and how to disable it. Check the link to find out about it.



I'm not familiar with react-boilerplate (React ecosystem is huge), but I guess my answer at least narrows down the search. Consider asking a separate question with react-boilerplate if you get confused.






share|improve this answer





















  • Thank you! What works is to move saga to global scope. Then it is not cancelled during route change!
    – user1665355
    Nov 10 at 15:43













up vote
1
down vote



accepted







up vote
1
down vote



accepted






I'm posting what we've gathered as an answer, so that this question is useful for future readers.



In redux-saga, sagas started via call() and fork() are cancelled recursively. Saga means a recursively cancellable task. So when a saga gets cancelled, you should check its parent saga, and so on.



This code snippet you've posted:



const withSaga = injectSaga({ key: 'login', saga });
export default compose( withReducer, withSaga, withConnect, )(LoginPage)


Google suggests that it uses this redux-saga + react-boilerplate example. It covers cancellation and how to disable it. Check the link to find out about it.



I'm not familiar with react-boilerplate (React ecosystem is huge), but I guess my answer at least narrows down the search. Consider asking a separate question with react-boilerplate if you get confused.






share|improve this answer












I'm posting what we've gathered as an answer, so that this question is useful for future readers.



In redux-saga, sagas started via call() and fork() are cancelled recursively. Saga means a recursively cancellable task. So when a saga gets cancelled, you should check its parent saga, and so on.



This code snippet you've posted:



const withSaga = injectSaga({ key: 'login', saga });
export default compose( withReducer, withSaga, withConnect, )(LoginPage)


Google suggests that it uses this redux-saga + react-boilerplate example. It covers cancellation and how to disable it. Check the link to find out about it.



I'm not familiar with react-boilerplate (React ecosystem is huge), but I guess my answer at least narrows down the search. Consider asking a separate question with react-boilerplate if you get confused.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 9 at 15:47









Andrey Moiseev

1,34642745




1,34642745












  • Thank you! What works is to move saga to global scope. Then it is not cancelled during route change!
    – user1665355
    Nov 10 at 15:43


















  • Thank you! What works is to move saga to global scope. Then it is not cancelled during route change!
    – user1665355
    Nov 10 at 15:43
















Thank you! What works is to move saga to global scope. Then it is not cancelled during route change!
– user1665355
Nov 10 at 15:43




Thank you! What works is to move saga to global scope. Then it is not cancelled during route change!
– user1665355
Nov 10 at 15:43


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53223958%2fsaga-always-cancelled%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Schultheiß

Android Play Services Check

Where to put API Key in Google Cloud Vision for PHP