You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:26:16