mplain
02/19/2022, 12:02 PMobject LoggingAsyncRunner {
private val log: Logger = LoggerFactory.getLogger(this.javaClass)
fun launch(job: () -> Unit) {
CoroutineScope(Dispatchers.Default).launch {
runHandlingErrors(job)
}
}
private fun runHandlingErrors(job: () -> Unit) =
try {
job()
} catch (e: IllegalArgumentException) {
log.warn("Async job exception", e)
} catch (e: Exception) {
log.error("Async job exception", e)
}
}
this cannot handle delay
, so I change job: () -> Unit
to job: suspend CoroutineScope.() -> Unit
, and also add suspend
to fun runHandlingErrors
object LoggingAsyncRunner {
private val log: Logger = LoggerFactory.getLogger(this.javaClass)
fun launch(job: suspend CoroutineScope.() -> Unit) {
CoroutineScope(Dispatchers.Default).launch {
runHandlingErrors(job)
}
}
private suspend fun runHandlingErrors(job: suspend CoroutineScope.() -> Unit) =
try {
job(~)
} catch (e: IllegalArgumentException) {
log.warn("Async job exception", e)
} catch (e: Exception) {
log.error("Async job exception", e)
}
}
now I get an error in fun runHandlingErrors inside try block (marked with ~) saying: no value passed for parameter p1
I then add CoroutineScope receiver to fun runHandlingErrors, and I get this warning:mplain
02/19/2022, 12:03 PMmplain
02/19/2022, 12:03 PMprivate suspend fun runHandlingErrors(job: suspend CoroutineScope.() -> Unit) =
coroutineScope {
try {
job()
} catch (e: IllegalArgumentException) {
log.warn("Async job exception", e)
} catch (e: Exception) {
log.error("Async job exception", e)
}
}
mplain
02/19/2022, 12:04 PMcoroutineScope {
mplain
02/19/2022, 12:04 PMmplain
02/19/2022, 12:05 PMSam
02/19/2022, 12:06 PMCoroutineScope
receiver from your job
, so it's just:
job: suspend () -> Unit
Sam
02/19/2022, 12:06 PMmplain
02/19/2022, 12:06 PMSam
02/19/2022, 12:07 PMCoroutineScope
, but not bothmplain
02/19/2022, 12:07 PMSam
02/19/2022, 12:07 PMlaunch
accepts a suspend CoroutineScope.() -> Unit
is a bit of an oddity which I find it best to ignore 😂)Sam
02/19/2022, 12:08 PMmplain
02/19/2022, 12:08 PMmplain
02/19/2022, 12:09 PMprivate fun runHandlingErrors(job: () -> Unit) =
try {
job()
} catch (e: IllegalArgumentException) {
log.warn("Async job exception", e)
} catch (e: Exception) {
log.error("Async job exception", e)
}
and
private fun runHandlingErrors(job: () -> Unit) =
try {
job()
} catch (e: IllegalArgumentException) {
log.warn("Async job exception", e)
throw e
} catch (e: Exception) {
log.error("Async job exception", e)
throw e
}
mplain
02/19/2022, 12:09 PMmplain
02/19/2022, 12:11 PMSam
02/19/2022, 12:16 PMlaunch
or async
will propagate upwards to the parent job, until they reach the root job (which is normally a coroutine scope).Sam
02/19/2022, 12:16 PMmplain
02/19/2022, 12:16 PMmplain
02/19/2022, 12:17 PMmplain
02/19/2022, 12:18 PMSam
02/19/2022, 12:19 PMasync
will return a Deferred
which you can use to see if the job threw an exception. In that case, your first example would make it always appear successful, while the second example would ensure the Deferred
also fails with the appropriate exceptionSam
02/19/2022, 12:19 PMasync
still cancels its parent job too, but that doesn't affect your example)