How can I make sure the coroutine was in fact cancelled, and did not just return or was cancelled by other means?
There is an obvious race-condition between checking job state and invoking cancel(). How can I know it was in fact cancelled?
val job = CoroutineScope(Dispatchers.Default).async { delay(1) }
if (!job.isCompleted)
job.cancel()
Maybe there is a better way, but one way is to cancel the job with a very specific exception and then check if it was cancelled with exactly the same exception. This is fairly easy if using
Deferredas in your example:At least on my machine I sometimes see it was cancelled by #1, sometimes by #2 and sometimes by none (completed successfully). As this is a race condition, it may be hard or even impossible to reproduce on other computers.
Surprisingly, I don't see a similar API for the
Job. Obviously, we can't get a result fromJob, but I don't see whygetCompletionExceptionOrNull()couldn't be added at theJoblevel, notDeferred. The only way I found is by using theinvokeOnCompletion, but if feels a bit hacky:Both solutions probably require additional testing for various cases like non-cancellable jobs, etc.