I have a SyncWorker class I am using to capture offline actions and relay them to the server. It works, but I am currently trying to improve the success rate by investigating cases of failed sync operations captured in logs. A substantial number of these failures were reported as missing the data provided for sync (stored in a local database). I initially assumed these to be indications of local database failures, but upon investigating specific cases of this failure I found that every single one (about a dozen investigated so far) was immediately preceded by the same operation succeeding. I am at a loss as to what may be causing these extra work instances, but the order of operations seems to be something like this:
The success case is currently set to return Result.success()
. The corresponding doWork
contents (located near the end of the method) are here:
if (response.isSuccessful) {
performCleanup(recordId, databaseResult.data)
Log.i(TAG, "$logInfo: Sync request succeeded")
return Result.success()
}
And the subsequent triggered failure, near the beginning of doWork
:
if (databaseResult.data == null) {
Log.e(TAG, "$logInfo: Model data not found, stopping worker")
return Result.failure()
}
Here is an example of the issue as it presents in logs, for ID 62bfd14d776c5e7f458ccb2a
(filtered somewhat):
And here is an example of enqueuing the work:
val constraints = Constraints.Builder().apply {
setRequiredNetworkType(NetworkType.CONNECTED)
}.build()
val request = OneTimeWorkRequestBuilder<SyncWorker>().apply {
setInputData(inputData)
setConstraints(constraints)
addTag(SyncWorker.syncWorkTag)
}.build()
val manager = WorkManager.getInstance(applicationContext)
manager.enqueue(request)
The issue is occasional (about 0.33% of all sync instances), but I'd love to root out these false negatives. I've been combing logs for the past few days looking for some kind of pattern to no avail (various app versions, Android versions, devices, etc.) and the developer pages for WorkManager have not gotten me anywhere either. I've been finding it hard to search for any issues related to this as well, getting mostly discussions of users that want their work to requeue itself. Any advice that could point me towards the why of this behavior would be greatly appreciated. Thanks.
Tested with work manager 2.7.0.
After overriding onStopped()
with log, I noticed that onStopped()
is called while worker is active.
After worker returns Result.success()
, the same worker is rescheduled again.
Assuming you're not the one that cancels the worker & reschedule, I went to documentation and after eliminating other possible reasons, only one left:
Your work's constraints are no longer met.
So this is what I figured as network can be unstable for some users:
onStopped()
.