What is the proper way to serialize execution of a...
# coroutines
a
What is the proper way to serialize execution of a coroutine, such that if its already running, it can be cancelled + joined before starting another one? I need to wait for the previous coroutine to actually cancel before starting the new coroutine. I have something like this, but am doubtful:
Copy code
val job:Job? = null

fun foo() {
  val oldJob = job  
  job = coroutinescope.launch {
    oldJob?.cancelAndJoin()
  }
}
s
I wonder if a flow with collectLatest could be a good solution here? Your approach doesn't necessarily look incorrect, though 👍
👍 2
d
join
and
cancelAndJoin
both guarantee that they will wait for the body of the coroutine to complete, whether or not it was cancelled. However,
invokeOnCompletion
blocks and the like are not guaranteed to run by the time
join
exits.
👍 1
z
This is a useful pattern, compose uses it in a few places. Especially when combined with an AtomicReference, which makes it makes it thread safe.
👍 1
a
Zach would
AtomicReference
be used for
oldJob
since its being assigned in one spot, but referenced (for cancel) in the new coroutine? If you have any snippets of this pattern I’d be interested in studying them.
z
Here is one and two in Compose
👍 1
a
Thanks Zach, I spent a few hours grokking those two examples and learned a few things (hopefully). Now I have this with
AtomicReference
Copy code
val externalScope : CoroutineScope = ...
val currentJob = AtomicReference<Job?>(null)

fun foo(...) {
    externalScope.launch {
        currentJob.getAndSet(coroutineContext.job)?.cancelAndJoin()
        ... do things ...
        }
    }
}
👍🏻 1