WorkManager: Why does failed unique work with the "APPEND" ExistingWork strategy not allow more work under the same name?
So I found the answer to my own question in this google issue tracker report.
Basically, unique work using the APPEND
strategy creates a WorkContinuation
where every new item is chained on as if we were to use the WorkContinuation#then
method. Failing or cancelling the chain then cancels all downstream work, and so this is intended behaviour.
The ticket suggests 2 approaches:
If you really want APPEND's behavior, then another thing you could do is to check for WorkStatuses of the WorkRequests, and if (all of them happened to be cancelled) use REPLACE instead of APPEND. Bear in mind, this is inherently racy, because your WorkRequests might not have cancelled yet. So make sure you have some synchronization primitives around your use of WorkManager's APIs.
and
The simplest way to do this is to not actually return Result.FAILED; if you always return SUCCEEDED and return the actual pass/fail bit (if needed) in the output data, you can make sure the chain always keeps running.
Which is what I'm already doing. Hope this helps someone else.
Important update regarding that matter: https://developer.android.com/reference/kotlin/androidx/work/ExistingWorkPolicy#append_or_replace
APPEND_OR_REPLACE
enum val APPEND_OR_REPLACE : ExistingWorkPolicy
If there is existing pending (uncompleted) work with the same unique name, append the newly-specified work as the child of all the leaves of that work sequence. Otherwise, insert the newly-specified work as the start of a new sequence.
Note: If there are failed or cancelled prerequisites, these prerequisites are dropped and the newly-specified work is the start of a new sequence.
That's probably the team's response to exactly this issue. This new ExistingWorkPolicy
is available in version 2.4.0-alpha01
.
EDIT AFTER FURTHER TESTING...
So it turns out the only thing this fixes is not being able to reuse the UniqueWorkContinuation
if for some reason it failed once. However, the main feature, e.g. being able to cancel a single WorkChain
when many Workchains
are queues with the same unique name still doesn't work. Typically, consider: WorkChainA
with CompressWorkerA
and UploadWorkerA
and then queuing WorkChainB
with CompressWorkerB
and UploadWorkerB
, all under the same UniqueWorkName
. Canceling or failing any Worker
in WorkChainA
will cause WorkChainB
never to run... Thus we still have to make sure to return Result.success()
every time. And don't use any cancelWorkByTag
or cancelWorkById
withing the UniqueWork
!