what’s the recommend pattern to launch a non-cance...
# coroutines
z
what’s the recommend pattern to launch a non-cancellable coroutine from within a cancellable
CoroutineScope
?
using
GlobalScope
works, but is it recommend?
a
Maybe with a
NonCancellable
context?
It also depends on your application. If the data returned is used by anything with a lifecycle, then it usually doesn’t need to be noncancellable. If it must live on regardless of the caller, then
GlobalScope
seems reasonable
z
what would the difference be between using
NonCancellable
and
GlobalScope
?
s
AFAIK you cannot with what's available in kotlinx.coroutines. Reason being that you're already within a cancelable context, so this would require writing a runner that can take into account a context switch?
If you figure this out please let me know :)
a
Someone else may clarify, but I believe usage wise they are similar. NonCancellable still has a job, thought it is always active, whereas globalscope doesn’t have a job in its context. For
NonCancellable
, you can wrap part of your execution with it, and leave the remaining executions cancellable. In that case, your full job will cancel prematurely if it is cancelled, just not within the noncancellable scope. You can probably still do this with
GlobalScope
though.
I think the biggest difference is that one replaces the scope whereas the other replaces the context
👍 1
z
basically I have an API like
Copy code
// invoked within a cancellable scope
processStarter.start { result ->
  // even if the scope is cancelled, this launch coroutine MUST be executed
  launch {
     // suspending function, which is why the `launch` above is needed
     mustDeliverResult(result)
  }
}
the
start { .. }
lambda is not tied to any coroutine and is just a callback that once returned, must deliver its result
I believe there are two solutions.
Copy code
launch(NonCancellable + Dispatchers.Unconfined) {
  mustDeliverResult(result)
}
and
Copy code
GlobalScope.launch(Dispatchers.Unconfined) {
  mustDeliverResult(result)
}
I’m also using
Dispatchers.Unconfined
too because I want that result delivered ASAP, and not posted to an executor or queued up. I’m not sure why I might choose one solution over the other
a
I think in your case either works. It comes down to what your function does. If your function needs to launch a new task, it’s easier to make it a normal function and use
GlobalScope.launch
. If your function is a suspended function and you want to make it noncancellable, it’s easier to use
withContext(NonCancellable) { ... }
You have the liberty of using either since you are in a scope.
👍 2
1
s
What I am not sure I understand is that if the parent scope gets cancelled, how does that prevent the child scope of not being cancelled. Which is what happens if you call
withContext
within another scope, right?
z
The lambda in
start { .. }
is a
(ProcessResult) -> Unit
, so it's not being called from any suspending context
s
Oh okay, I missed that part. Thanks!