In a suspend function is it possible to launch a c...
# coroutines
c
In a suspend function is it possible to launch a coroutine with the current scope and return immediately? The
coroutineScope
function waits for the block's completion before returning, but I want to just
launch
something with the current scope, fire and forget
j
That would be the opposite of the convention on how
suspend
functions should behave. Why use a
suspend
function if you want to fire and forget? Just use a regular function defined as an extension on
CoroutineScope
e
I'd rather push the
launch
into the callers, make it explicit that they are firing-and-forgetting
j
Yeah if the launch is the only thing in the function, it's even better
p
I'd probably return the Job from such a launch-only function as it would allow you to join or cancel if required
c
Okay, here's some more context on my use case. In layer A of my architecture we have defined a coroutine scope, which is automatically cancelled when the user finishes their task. Layer A uses that scope to call suspending functions in layer B to perform some domain logic for each user action. For one such action, layer B must perform some some operations to update the UI state, as well as kick off this fire and forget operation, which lives within layer C, and can fail silently. Since we are already within a coroutine in layer B at this point, using the auto-closing scope defined in layer A, I was hoping to be able to perform this operation in layer C using the same scope we are already in, so that it will be automatically cancelled if the user finishes their task, just like all the other operations. The only difference is that we want to return immediately once this operation has started, so that we don't hold up layer B from updating the UI state (which is not dependent on this fire and forget operation)
p
Sounds like you want to
launch
it. It will hold up normal completion of the scope (as it will wait for all children to complete) but not the calling function as you desire. It will also be cancelled when the scope is cancelled (or a failure occurs in the scope).
But you'll need to pass down or make available the A scope to the method and call
launch
on that rather than the enclosing
coroutineScope
block (if any).
c
But how do I obtain a reference to the coroutine scope being used for the current coroutine, in order to call
launch
?
p
I wonder if you could add a reference to the A scope into the CoroutineContext as a custom Element and pull it out (as it should propagate to child contexts and be available from layer C)
c
There's no way other than manually passing down the scope? I was just thinking if the
coroutineScope
function exists, which automatically gives us a reference to the current scope, shouldn't we be able to automatically get a reference to the current scope for my use case as well? Launching something and not waiting for it to return?
Interesting idea, I will try that, thanks!
p
coroutineScope creates a new child scope with its own Job which is why it waits for all its children to complete before returning.
Probably worth adding if you launch on A it won't get cancelled if B or C gets cancelled. That may not matter for your usecase.
c
Gotcha. Maybe I should look into `coroutineScope`'s implementation to see how it reuses the outer scope so I can do something similar
What do you mean exactly by B or C gets cancelled?
Because they don't have their own scopes which can be cancelled
The goal is for everything to use the scope defined in A, and nothing gets cancelled until A automatically cancels its scope when applicable
p
If you launch on A as part of an operation in C (assuming it has its own scope), it'll be a sibling not a child (or uncle in this case). C won't wait until it completes (which you want) but if you cancel C it won't propagate to the launched job automatically.
That should be fine then - but if you still had a coroutineScope block in C it would have its own child scope of A
c
Gotcha. Yeah it sounds like I don't need
coroutineScope
at all for my use case, I was just thinking I want to do something similar to what that function does in terms of reusing the outer scope
l
Make your function take a
CoroutineScope
as a parameter or receiver.
c
Yeah I might have to just do that, passing the scope down throughout the architecture layers. Was hoping instead there would be some way to reference the current coroutine context/scope from within a coroutine, but it appears not.
l
Technically, there are ways, but it's hard because it's dangerous, always, so no point in seeking painful future debugging sessions, and product wreckage 😉
The danger would be that you can easily come to a situation where there's a crash that you don't understand how it's crossing boundaries it should not, or it would be that some coroutine is never completing, and you don't understand why.