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 () -> UnitSam
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)