awaitAll fails fast, I want a function that runs a...
# coroutines
f
awaitAll fails fast, I want a function that runs all n coroutines i launch to completion irrespective of whether they succeed or fail and then i'll decide how to handle the outcome, which function is that?
f
wrap them in a
supervisorScope
f
🤔 come to think of it, shouldn't it just be joinall though?
@Francesc @jw appreciate the input and not disagreeing with you, but what's the difference with simply joinAll and supervisor scope in this case? in sequential code i can just
Copy code
result1 = doThis() //Result
      result2 = doThis() //Result
      result3 = doThis() //Result

      //do something with the results
i just want to do the same except 1) simultaneously 2) without short circuiting all three on one failure 3) without messing with the results (ie by faking a successful result with onrecover etc)
j
i would assume joinAll would immediately propagate cancelation, but i would have to check to be sure
f
in that case it seems to me joinAll behaves the same as awaitAll, so what's the difference between those two then? 😅 apologies, i just find coroutines kinda confusing and full of subtle differences and gotchas
j
awaitAll is for a list of deferred and getting their results as a list
joinAll is for a list of jobs
f
= is the difference that joinall launches them immediately and awaitall you instantiate and then you can pass it around before launching it?
j
both operate on already launched coroutines. A
Job
is returned from a
launch { }
. A
Deferred
is returned from an
async { }
.
the sole difference (kinda) is whether it returns a value or not
f
ah, mine are definitely supposed to return values (ie they're not fire and forget) basically in //do something with the results, i need to access the results lol
d
Could you share your code?
joinAll
and
awaitAll
would have no effect if you launch them as child coroutines as in that case coroutine which is supposed to defer the result will just propagate it up the job hierarchy. If no handler is installed in top-level coroutines or scope it will propagate it upwards to the thread’s uncaught exception handler. This is the reason why
supervisorScope
was recommended to you in the first place. This way parent job is
SupervisorJob
making your coroutines launched with
async
now top-level coroutines which behaves differently and won’t now propagate the exception meaning you would be able to get the result of coroutines that did not fail.
l
Wrap the code to run in
runCatching
inside your async blocks, and then use
awaitAll
on it and decide what to do.
f
runCatching
is tricky to use with coroutines as you could easily swallow the cancellation exception
l
You're not using it over the
coroutineScope { … }
that contains the
async { … }
blocks, so it should be fine. You can also make a
cancellable()
extension for
Result<T>
that rethrows `CancellationException`s.
f
by suggesting to make an extension (so not using the function itself) you just made my point
l
What you put in parentheses doesn't seem to match the reality of what I wrote. I'm talking about using cancellable with runCatching, though I specified it might not be necessary in the given use case.
f
sorry hands full and haven't been able to reply as much or in as much details as I'd like but
Copy code
suspend fun doStuff(){
      result1 = doThis() //Result
      result2 = doThis() //Result
      result3 = doThis() //Result

      //do something with the results
}
Result here means runCatching { ... } yielding a Result on all three I know runCatching is unidiomatic, especially inside coroutines, but that's the standard in these codebases and I'm unable to change that at the moment I don't think awaitAll would do what I'm asking, since the docs literally state awaitAll fails fast ie on the first error in any of the three, that's not what I want, I want them all to finish even if one or they all fail, no different to as if they were sequential code (like above), only that instead of sequantial run, they run simultaneously
oh, and there is no handler for any exceptions on this or a higher level. so that's out of the picture too. but since we're doing runCatching, that shouldn't matter - any exception resulting from any of the three should be contained in the Result
l
Don't forget to wrap in a local
coroutineScope { }
f
to be perfectly honest, I'm so confused by all the gotchas and footguns in the coroutines library that I'd much prefer using Arrow to wrap it with simpler, easier to understand abstractions, less footguns and an api that guides you into not making mistakes looking at Roman and others answers to even fairly simple questions on Stackoverflow about coroutines, they seem to me surprisingly often to be like "ah yes you're doing this intuitive thing which is actually a huge no no"... don't get me wrong of course coroutines are amazing and powerful and we should all be grateful for them and the work put into them, but yeah, I find the API to rely a bit too much on users' intimate knowledge, best behavior and ability not to make easy-to-make mistakes