question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Forked subtasks should be cancelled when parent is cancelled (?)

See original GitHub issue

Imagine I have Task1 that forks Task2 that forks Task3

Now I cancel Task1, which cause a SagaCancellationException inside Task1. But by default seems forked tasks Task2 and Task3 are not cancelled and can stay alive even if the parent Task1 is cancelled.

Is it supposed to be handled by redux-saga, or should I propagate the cancellation myself to forked subtasks?

With this code I successfully propagate the cancellation to subtasks but it requires additional boilerplate:

export default function* task1() {
  let subtasks = [];
  try {
    subtasks.push(yield fork(task2));
    subtasks.push(yield fork(task3));
    while ( true ) {
      yield take("SOME_EVENT_THAT_RESTART_SUBTASKS");
      yield subtasks.map(cancel);
      subtasks = [];
      subtasks.push(yield fork(task2));
      subtasks.push(yield fork(task3));
    }
  }
  catch(e) {
    if ( e instanceof SagaCancellationException ) yield subtasks.map(cancel);
    else throw e;
  }
}

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:17 (13 by maintainers)

github_iconTop GitHub Comments

3reactions
yelouaficommented, Mar 31, 2016

I’m thinking of integrating this into the next release.

The mental model is that a parent + forked children represent a whole unit: a tree with multiple execution paths.

Here is what I propose

  1. Cancellation of parent automatically triggers cancellation of all currently active forked tasks (we cancel the whole execution tree)
  2. A parent terminates when :
    1. its own body terminates and
    2. forked (and attached) tasks terminate (the whole execution tree must terminate)
  3. Provide an additional setting to fork detached children (the default for children is to be attached). The cases for this IMO should be pretty rare so rather than create another effect, W’ll just provide this as a config option on the fork itself, something like : yield fork({fn, detached: true}, ...args) or yield fork(fn, ...args).detached

(1) would handle common client side scenarios: when an UI page is unloaded we’d typically like to cancel all the tasks related to that page

(2) would handle server side scenario: when we do render on the server, w’d like to wait for all triggered tasks to terminate before sending the HTML to the client (see #149)

(3) would provide an alternative for other cases

1reaction
yelouaficommented, Feb 8, 2016

@slorber In this example you fork tasks then immediately join them

function* handleStamplesPaginationAndFiltering(model) {
  const subtasks = [];
  try {
    subtasks.push(yield fork(stamplePaginateSaga,model))
    subtasks.push(yield fork(stampleFilterUpdatesWatcher,model))
    yield subtasks.map(join)
  }
  catch(e) {
    if ( e instanceof SagaCancellationException ) {
      yield subtasks.map(cancel);
    }
  }
}

why not simply use

function* handleStamplesPaginationAndFiltering(model) {
  yield [
    call(stamplePaginateSaga,model),
    call(stampleFilterUpdatesWatcher,model)
  ]
}

if handleStamplesPaginationAndFiltering is cancelled from a parent Saga, then the cancellation would propagate automatically to the current effect which is the parallel yield [...]. Parallel effect cancellation means cancellation of all sub-effects

Read more comments on GitHub >

github_iconTop Results From Across the Web

Solved: Cancel Sub-tasks when parent is canceled, revert t...
I am looking for a way to cancel sub-tasks if a parent is canceled (only those that are to do or in progress)...
Read more >
Task Cancellation | Redux-Saga
In this section we'll review cancellation in more detail. Once a task is forked, you can abort its execution using yield cancel(task) ....
Read more >
swift - Why are nested tasks not canceled when they parent ...
Because you are using Task , which is for unstructured concurrency. As the docs say, it is not a subtask, but a new...
Read more >
Task cancellation | redux-saga
Once a task is forked, you can abort its execution using yield cancel(task) . Cancelling a running task will throw a SagaCancellationException inside...
Read more >
JEP 437: Structured Concurrency (Second Incubator)
Often, a task such as handle() should fail if any of its subtasks fail. ... the call to join() , both forks are...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found