I'm having troubles using Coroutines in WorkManager. Here is the snippet of Worker class.
class ExampleWorker (context, workerParams) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
//set foreground
try {
val result = provider.getMeResult()
if(result.success) return@withContext Result.success
else return@withContext Result.failure()
} catch(e: Exception) {
handleErrors()
return@withContext Result.failure()
} finally {
//clean up tasks
}
}
}
Here is the getMeResult()
class Provider {
private val resultState = State()
private val exceptionHandler = CoroutineHandler { _, throwable ->
//set result state to failed
resultState.status = FAILED
resultState.code = someErrorCode
}
private val runScope = CoroutineScope(Dispatchers.Default + exceptionHandler)
private val jobsList = mutableListOf<Job>()
suspend fun getMeResult(): State {
val runJob = runScope.launch {
someLongRunningTask() // spits result out to a channel, say itemsChannel
}
itemsChannel.consumeEach {
//spawn a new coroutine to run the job concurrently
val job = runScope.launch {
somebackgroundTask() //Point A
}
jobsList.add(job)
}
//wait for all jobs to complete
jobsList.joinAll()
}
//wait parent coroutine to complete
runJob?.join()
//once you reach here, looks everything has worked. Update run state to complete
resultState.status = COMPLETE
return resultState
}
Ideally, this works as expected and result status is returned. However, whenever an error is thrown from Point A, exception handler receives the error and getMeResult() returns COMPLETE value. Worker catch block is never invoked, no error code was set. How can I make this work so that the Worker gets failed status when an error occurs? Also, when I cancel runJob within exceptionHandler, it fires multiple CancellationException with root cause as the actual exception type, but that cause is always null if I catch it within the parent Coroutine.
Hope it makes sense.