【问题标题】:WorkManager: Why does failed unique work with the "APPEND" ExistingWork strategy not allow more work under the same name?WorkManager:为什么使用“APPEND”ExistingWork 策略失败的唯一工作不允许在同名下进行更多工作?
【发布时间】:2020-06-23 01:20:19
【问题描述】:

假设我们正在开发一个消息传递应用程序,我们希望将消息发送到给定的对话中,这些消息的顺序仅在该对话中很重要,如果应用程序被置于后台,我们希望保证消息将被发送。

WorkManager#beginUniqueWork 方法似乎很适合这种情况,其中uniqueWorkName 将是一些对话 id,ExistingWorkPolicy.APPEND 将用作工作策略以保持工作按计划进行。

到目前为止,在我的应用程序中,只要每个 Work 返回 Result.SUCCESS,那么任何未来计划的工作都会按预期执行。但是,如果一条特定消息未能以致命方式发送并且我返回 Result.FAILURE,那么所有未来使用相同对话 id 的工作似乎永远不会达到我对 Worker#doWork() 的实现。

在挖掘EnqueueRunnable 类的源代码之后,这似乎是一个非常慎重的选择。我真的不明白为什么会这样?奇怪的是,如果 uniqueWorkName 失败,该名称将在应用程序的剩余生命周期中变得不可用(这会在终止应用程序时持续存在)。

此外,我想知道是否有人对此有很好的解决方案,或者知道这是否会在 WorkManager 的未来版本中发生变化。到目前为止,我能想到的最好的事情是返回Result.SUCCESS,但在输出Data 中编码我自己的失败状态,这样任何工作的观察者都知道它失败了。然而,这有点尴尬,并且对于代码的未来维护者来说并不是很明显(并且在查看给定 Work 的日志时可能会有点混乱)。

也许我对独特作品的预期用途是完全错误的,并且有更好的解决方案。任何想法将不胜感激,谢谢!

【问题讨论】:

  • 如果不更好地了解您要达到的目标,就很难回答。如您所见,返回Result.FAILURE 的效果是,任何依赖于此的工作也将被标记为失败并且不会运行。这个想法是一个 FAILURE 向 WorkManager 表明在这个链中不能做更多的事情。另一种看待它的方式是,这个返回值用于向 WorkManager 指示下一步要做什么(SUCCESS => continue, FAILURE => stop, RETRY => re-run the current worker)。
  • @pfmaggi 这对于在链入队之前映射出依赖关系的工作链来说都是非常有意义的,但这里我说的是 uniqueWork,特别是如果一个独特的工作失败,所有未来发布到同名的工作将永远不会被安排,即使在发布最新的 uniqueWork 时,当前没有工作正在执行。基本上一旦失败,那个特定的uniqueWorkName 在应用程序的剩余生命周期中将无法使用,这对我来说是出乎意料的。
  • @pfmaggi 感谢您的反馈,我想要实现的哪一部分不清楚?我试图在前 2 段中描述这一点,但如果您认为缺少某些内容,我会添加更多信息
  • 重新阅读你的前两段,这很有意义。但是话又说回来,如果您无法发送链中的一条消息,您想做什么?只是发送其他人(缺少消息)或重试?就个人而言,我认为最好的选择是重试发送“失败”消息。您在哪些情况下返回失败?
  • 一个特殊的例子是,如果我们尝试发送消息的时间过长,那么我们可能希望发送失败并将其报告给用户,然后他们可以决定我们是否应该重试(也许消息现在已过期)。正如我所提到的,现在我只是返回Result.SUCCESS 并将一些失败代码放入输出Data,但现在我真的不想调用Result.FAILURE,否则对话变得无法使用,这看起来很奇怪我!

标签: android android-jetpack android-workmanager


【解决方案1】:

所以我在this google issue tracker report 中找到了我自己问题的答案。

基本上,使用APPEND 策略的独特工作会创建一个WorkContinuation,其中每个新项目都被链接起来,就好像我们要使用WorkContinuation#then 方法一样。失败或取消链然后取消所有下游工作,因此这是预期的行为。

票证建议两种方法:

如果您真的想要 APPEND 的行为,那么您可以做的另一件事是检查 WorkRequest 的 WorkStatuses,如果(所有这些都恰好被取消)使用 REPLACE 而不是 APPEND。请记住,这本质上是活泼的,因为您的 WorkRequests 可能尚未取消。因此,请确保您在使用 WorkManager 的 API 时有一些同步原语。

最简单的方法是不实际返回 Result.FAILED;如果您始终返回 SUCCEEDED 并在输出数据中返回实际的通过/失败位(如果需要),则可以确保链始终保持运行。

这是我已经在做的事情。希望这对其他人有帮助。

【讨论】:

  • 在每种情况下返回 Result.success() 确实起到了作用。我个人使用 EventBus 发布任何以前的结果。感谢您的提示!
【解决方案2】:

关于此事的重要更新: https://developer.android.com/reference/kotlin/androidx/work/ExistingWorkPolicy#append_or_replace

APPEND_OR_REPLACE

枚举值 APPEND_OR_REPLACE : ExistingWorkPolicy

如果 存在具有相同唯一性的现有待处理(未完成)工作 名称,将新指定的工作附加为所有叶子的孩子 的工作顺序。否则,将新指定的工作插入为 新序列的开始。

注意:如果有失败或取消 先决条件,这些先决条件被删除,新指定的 工作是一个新序列的开始。

这可能正是团队对这个问题的回应。这个新的ExistingWorkPolicy 在版本2.4.0-alpha01 中可用。

进一步测试后编辑...

因此,这个修复的唯一问题是如果由于某种原因失败了一次,则无法重用 UniqueWorkContinuation。但是,主要功能,例如当许多Workchains 是具有相同唯一名称的队列时,能够取消单个WorkChain 仍然不起作用。通常,考虑:WorkChainACompressWorkerAUploadWorkerA,然后将 WorkChainBCompressWorkerBUploadWorkerB 排队,都在同一个 UniqueWorkName 下。在WorkChainA 中取消或失败任何Worker 将导致WorkChainB 永远不会运行......因此我们仍然必须确保每次都返回Result.success()。并且不要在UniqueWork 中使用任何cancelWorkByTagcancelWorkById

【讨论】:

    【解决方案3】:

    同理,感谢您对此问题的调查。

    玩了一段时间找到最佳解决方案后,目前这个对我有用

    startUpload() {
    
       workManager.pruneWork()
       //Prunes all eligible finished work from the internal database.
    
       photoAdapter.data.forEach {
          val workRequest = OneTimeWorkRequestBuilder<FileUploadWorker>()
                .setInputData(workDataOf(IMAGE_PATH_PROP to it.path))
                .addTag(UPLOADER_TAG)
                .build()
    
          workManager.enqueueUniqueWork(UNIQUE_WORK_TAG, ExistingWorkPolicy.APPEND, workRequest)
       }
    }
    

    调用“pruneWork”可以忘记取消或失败的工作。 但是,我想,这个解决方案可能有警告,所以要小心。

    另一个想法可能是这样的:

    workManager.getWorkInfosForUniqueWork(UNIQUE_WORK_TAG).get().forEach {
    
                if ( it.state == WorkInfo.State.FAILED || it.state == WorkInfo.State.CANCELLED) {
                    //Redefine your UNIQUE_WORK_TAG
                    UNIQUE_WORK_TAG = UUID().toString()
                    return
                }
            }
    

    尝试查找失败的 WorkInfo 并“切换”到新的唯一工作标签。 更好的方法值得赞赏。

    附言"androidx.work:work-runtime-ktx:2.3.4" 除了 (KEEP,REPLACE,APPEND) 之外没有新的 ExistingWorkPolicy

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-23
      • 2013-03-23
      • 1970-01-01
      相关资源
      最近更新 更多