WorkManager existing work policy APPEND_OR_REPLACE doesn't behave as expected
Asked Answered
M

1

9

I'm currently using a CoroutineWorker from androidx.work:work-runtime-ktx:2.5.0.

What I'm trying to achieve is:

  1. Enqueue workers with beginUniqueWork and same uniqueWorkName, with policy ExistingWorkPolicy.APPEND_OR_REPLACE.
  2. This will run the workers sequentially, and if a work fails or get cancelled, the expected behavior will be, according to the documentation:

If there are failed or cancelled prerequisites, these prerequisites are dropped and the newly-specified work is the start of a new sequence.

And what's happening is, all or the queued workers gets cancelled if a previous one also gets cancels (or fails). And this should be the expected behavior of ExistingWorkPolicy.APPEND but not ExistingWorkPolicy.APPEND_OR_REPLACE.

expected behavior -> actual behavior

Any ideas why this is happening? How to avoid queued unique workers to also get cancelled?

Metalinguistics answered 10/5, 2021 at 8:36 Comment(3)
I am also looking for the answer to this but could not find it. Temporarily, I used return result success for Worker in any case so the chain continues. I suggest you also check here: twitter.com/danlew42/status/1214562086585421826?s=20Hat
Thanks for your help, unfortunately that won't work for my use case since I want to also be able to cancel the unique work. Returning always success wouldn't help in that case.Metalinguistics
https://mcmap.net/q/1317104/-android-worker-existingworkpolicy-append_or_replace-is-not-acting-as-expected might help explain why it happened.Phenazine
G
8

The name of APPEND_OR_REPLACE is misleading, by reading this you will think that this Worker will REPLACE the previous worker in case of failure, or APPEND if it is RUNNING, which is wrong!

APPEND_OR_REPLACE means APPEND this worker to the running chain OR REPLACE the chain with a new one if the previous failed (create a new chain and start over, it is like a hard reset)

pseudo code

if (getChainWithUniqueTag(TAG).status == CANCELLED || FAILED) {
    createNewChine()
}
addRequestToChainWithTag(TAG,request)

Now It should make more sense, it is about the state of current chain and not the Work


To confirm this more, try to start a worker1 with a unique name, and then fail it (by calling Result.failure) and then create another worker2 with APPEND with the same unique name, worker2 will fail directly before starting because it belongs to a failing chain.

If you try the same scenario but with APPEND_OR_REPLACE, worker2 will start a new chain and continue working normally.

Consider this example :

val request1 = OneTimeWorkRequestBuilder<SleepWorker>()
                .setInputData(workDataOf(KEY_BREAK_AT to 5))
                .build()

val request2 = OneTimeWorkRequestBuilder<SleepWorker>()
                .build()
workManager.enqueueUniqueWork(
    TAG,
    ExistingWorkPolicy.APPEND_OR_REPLACE,
    request1
)
// Infinite loop
while (workManager.getWorkInfoById(request1.id).get().state == WorkInfo.State.RUNNING){}

workManager.enqueueUniqueWork(
    TAG,
    ExistingWorkPolicy.APPEND_OR_REPLACE,
    request2
)

SleepWorker

class SleepWorker(context: Context, parameters: WorkerParameters) :
        CoroutineWorker(context, parameters) {
        override suspend fun doWork(): Result {
            val breakAt = inputData.getInt(KEY_BREAK_AT,-1)
            repeat(10) {
                if(it == breakAt) return Result.failure()
                println("$it")
                delay(1000L)
            }
            return Result.success()
        }
}

Now in this case, request1 will fail, and then we start request2 and it will starts normally, because the FLAG is APPEND_OR_REPLACE, If the flag is APPEND then request2 will fail.

PS: try to move the second enqueueUniqueWork for request2 before the infinite while loop, request2 will fail too. makes sense no ?

because when we called enqueueUniqueWork the chain was good at that time, and for that the job has been added to that chain successfully.

Gleeman answered 1/11, 2021 at 14:9 Comment(2)
Best explanation on the topic!Barnaba
This explains the behaviour. But Is there an official documentation, that explains this behaviour with the chain? This seems to be hidden and I can not find any official documentation.Nature

© 2022 - 2024 — McMap. All rights reserved.