CoroutineWorker的doWork方法在Job取消后自动重启问题求助
问题:CoroutineWorker返回Result.failure()后自动重启任务
执行14次服务器API调用时,首次执行到第14次API时触发以下错误:
kotlinx.coroutines.JobCancellationException: Job was cancelled; job=JobImpl{Cancelling}@c8489c9 kotlinx.coroutines.JobCancellationException: Job was cancelled; job=JobImpl{Cancelling}@c8489c9 Job was cancelled Work [ id=690a0f6f-e2e4-4ea2-baaf-86650b02608b, tags={ xxx.DownloadWorker,download_entity_service_tag } ] was cancelled androidx.work.impl.WorkerStoppedException at androidx.work.impl.WorkerWrapper.interrupt(WorkerWrapper.kt:348) at androidx.work.impl.Processor.interrupt(Processor.java:439) at androidx.work.impl.Processor.stopWork(Processor.java:259) at androidx.work.impl.utils.StopWorkRunnable.run(StopWorkRunnable.kt:49) at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644) at java.lang.Thread.run(Thread.java:1012)
DownloadWorker核心代码如下:
class DownloadWorker(context: Context, parameters: WorkerParameters ) : CoroutineWorker(context, parameters) { private val tag by lazy { this::class.java.simpleName } private lateinit var wifiLock: WifiManager.WifiLock override suspend fun doWork(): Result { val syncType = getSyncType() val progress = applicationContext.getString(R.string.download_worker_start_download) displayServiceNotification(createForegroundInfo(progress)) acquireWifiLock() runCatching { download(getSyncMethod(),DataToBeSyncedExtractor.generate(syncType)) finishDownloadProcedure(syncType) }.onFailure { w(it) releaseWifiLock() return Result.failure() } releaseWifiLock() return Result.success() } ...其他代码 }
断点显示代码正确进入onFailure分支并返回Result.failure(),但doWork方法却自动重启,重新下载全部14个API的数据,最终无错误完成。预期返回Result.failure()后不会从头重启任务,寻求原因及解决办法。
原因分析
- 任务被强制终止而非正常失败:错误栈中的
WorkerStoppedException和JobCancellationException表明,任务是先被系统/WorkManager强制取消,触发协程Job取消后才进入onFailure分支。此时WorkManager会判定任务为意外终止,而非用户主动返回失败,因此会触发默认重试逻辑。 - 默认重试策略生效:WorkManager的
WorkRequest默认配置了重试策略(如线性回退重试),当任务被意外取消或抛出未捕获异常时,会自动重启任务。
解决办法
1. 区分取消场景和业务失败
在doWork中单独捕获WorkerStoppedException,明确区分任务被系统取消和业务逻辑错误的场景,避免触发重试:
override suspend fun doWork(): Result { val syncType = getSyncType() val progress = applicationContext.getString(R.string.download_worker_start_download) displayServiceNotification(createForegroundInfo(progress)) acquireWifiLock() return try { download(getSyncMethod(), DataToBeSyncedExtractor.generate(syncType)) finishDownloadProcedure(syncType) releaseWifiLock() Result.success() } catch (e: WorkerStoppedException) { // 任务被系统强制取消,返回failure但不触发重试 releaseWifiLock() Result.failure() } catch (e: Exception) { // 业务逻辑错误,根据需求决定是否重试 w(e) releaseWifiLock() Result.failure() } }
2. 显式配置重试策略
创建WorkRequest时,自定义重试规则,比如禁用重试或仅在特定错误时重试:
val downloadWork = OneTimeWorkRequestBuilder<DownloadWorker>() // 禁用重试:自定义RetryPolicy始终返回false .setRetryPolicy(object : RetryPolicy { override fun shouldRetry(result: Result): Boolean { return false } }) .build()
如果需要针对特定错误重试,可以在shouldRetry中判断result的错误类型。
3. 排查任务被取消的根源
- 检查任务执行时长是否超过WorkManager后台Worker的默认超时限制;
- 确认前台服务通知配置正确,避免系统将Worker判定为后台任务而终止;
- 排查是否存在系统资源紧张导致的任务终止。
内容的提问来源于stack exchange,提问作者ricP87
相关产品推荐
相关产品推荐

