Richard Schielek
12/03/2024, 4:59 PMsuspend fun foo() {
MDC.put("key", "value")
withContext(MDCContext()) {
bar()
}
}
suspend fun bar() = withContext(Dispatchers.Default) {
// ...
}
vs
suspend fun foo() {
MDC.put("key", "value")
bar()
}
suspend fun bar() = withContext(Dispatchers.Default + MDCContext()) {
// ...
}
Mario Niebes
12/03/2024, 5:04 PMRichard Schielek
12/03/2024, 6:16 PMkevin.cianfarini
12/03/2024, 6:45 PMbar
should execute on both the default dispatcher and the MDCContext. For that reason the second sample is not a leaky implementation and should be preferred.kevin.cianfarini
12/03/2024, 7:05 PMSuspend functions should be main-safe, meaning they’re safe to call from the main thread. If a class is doing long-running blocking operations in a coroutine, it’s in charge of moving the execution off the main thread using. This applies to all classes in your app, regardless of the part of the architecture the class is in.withContext
Richard Schielek
12/03/2024, 9:42 PMDaniel Pitts
12/03/2024, 9:48 PMRichard Schielek
12/04/2024, 8:19 AMbar
cannot rely on being called right after the MDC was modified. foo
on the other hand has full knowledge of the MDC being modified. It needs to ensure the MDC is propagated correctly.
Conclusion: First variant where foo
is setting the MDCContext
the is correct. Second variant where bar
is setting it is error-prone.
Example
// correct
suspend fun foo() {
MDC.put("key", "value")
// must be called before the next suspension point
withContext(MDCContext()) {
delay(500)
bar()
}
}
suspend fun bar() = withContext(Dispatchers.Default) {
// ...
}
vs
suspend fun foo() {
MDC.put("key", "value")
delay(500) // this will break
bar()
}
suspend fun bar() = withContext(Dispatchers.Default + MDCContext()) {
// ...
}
Hugo Costa
12/06/2024, 8:10 AMfun validateNetwork(input: ValidateNetworkInput) = runBlocking(Dispatchers.Default + MDCContext()) {
MDC.put("externalValidationID", input.validationUniqueIdentifier)
withContext(MDCContext()) {
validateNetworkHandler.handle(input, identity)
}
}
And within the handle function
suspend fun handle(input: ValidateNetworkInput, identity: Identity): ValidateNetworkOutput = coroutineScope {
stuff
}
It's important to do the coroutineScope otherwise the map gets lost btwRichard Schielek
12/06/2024, 8:59 AMIt's important to do the coroutineScope otherwise the map gets lost btwAre you sure about that? To my understanding only
withContext(MDCContext())
is relevant. You should be able to omit it in runBlocking
and you shouldn't be forced to create a new scope for propagating the MDC.Hugo Costa
12/06/2024, 9:35 AM