WorkManager CoroutineWorker 的流取消

WorkManager CoroutineWorker's stream cancellation

我有以下设置:

override suspend fun doWork(): Result = coroutineScope {
    flowOfEvents
        .onEach(eventChannel::send)
        .launchIn(this)  

    if (isQueueEmpty()) return@coroutineScope Result.success()

    ... 
}

我看到的是以下内容:当 isQueueEmpty() 为真时,我 return Result.success() 并且我希望 flowOfEvents...launchIn(this) 流为 disposed/cancelled 也一样,但我不断从该流接收事件。

我是不是做错了什么?

launchIn(this) 捕获作业并在每个 return 语句工作之前显式调用 job.cancel(),但感觉 unnecessary/wrong.

经过一些研究,很明显这是 Kotlin 协程行为,与 WorkManager 完全无关。

  • Flow<Event> 是一项 never-ending 的工作
  • 根据定义,父协程等待子协程完成

鉴于这两点,现在很明显为什么我从父协程返回后仍然收到 Events。

解决方法:在父协程返回前调用coroutineContext[Job]?.cancelChildren()

override suspend fun doWork(): Result = coroutineScope {
    flowOfEvents
        .onEach(eventChannel::send)
        .launchIn(this)  

    if (isQueueEmpty()) {
        coroutineContext[Job]?.cancelChildren()
        return@coroutineScope Result.success()
    }

    ... 
}

注意:调用父对象的 cancel() 会抛出 CancellationException,这在 WorkManager 的上下文中意味着 Worker#doWork 方法实际上会产生结果在失败的工作中。