# coroutines

Satyam Agarwal

04/28/2021, 8:00 PM
Hei. @elizarov (apologies for tagging you directly) I wanted to get your rationale over
GlobalScope.launch { … }
I read this article which makes sense, and I almost always use
withContext(AppropriateDispatcher) { … }
to offload heavy jobs. I have a ktor server that receives around 260 req/sec and logs request and responses while receiving and responding, along with actual response. This is done via an interceptor. Now I don’t care much about logging, so I was thinking to do something like
GlobalScope.launch(MDCContext()) { interceptor.request.log(...) }
so that logging is eventually done, but the interceptor can
immediately. In fact, I was thinking to do this to pretty much every logging, Do you think it is a good way of doing the intention. What can be the consequences in regards to threads and CPU if a lot of logging suddenly starts offloading to GlobalScope ? Anyone can help me as well 🙂 Any and all feedback is much appreciated.


04/28/2021, 8:01 PM

Zach Klippenstein (he/him) [MOD]

04/28/2021, 8:04 PM
Note that
doesn’t specify a dispatcher, which means that in most cases the
dispatcher will end up getting used. So whatever that implies about thread behavior will apply to


04/28/2021, 10:28 PM
Just wondering how we can do fire and forget without waiting for result then without using GlobalScope.


04/29/2021, 7:31 AM
Create your own scope singleton
Copy code
object LoggerScope = CoroutineScope(...+ SupervisorJob())
Or better inject it using DI


04/29/2021, 8:46 AM
GlobalScope.launch { log(...) }
is an exceptionally bad idea. First of all, you can get your back-to-back log statements misordered, vastly complicating future trouble-shooting that logging was supposed to help with in the first place. Now, you probably were trying to solve a problem of "logging being slow" by offloading it to the background, but instead you've created a situation where if your logging is indeed slow, then its slowness will manifest in your app running out of memory, making it way harder to figure out why is that your app is not working as good as indented.
The worst part of it, is that if you accidentally make a bug like trying to log something in an endless loop, it'll become way harder to spot. Instead of just slowing your app down (as the bug like this should), it will slowly eat your memory, resulting in all kind of weird effects throughout your app.
If you really want to offload logging into background, then use an actor pattern: create a channel with some decently sized buffer and launch a coroutine that reads from this channel sequentially and logs; send your stuff that needs to be logged in your app to that channel for your coroutine to log.

Satyam Agarwal

04/29/2021, 9:00 AM
I actually I tried this in last night, and this is exactly what happened. Threads count that was 50 almost all the time slowly increased to to about 100, almost all the threads slowly transitioned to TIMED_WAITING, heap space started to grow slow, but after almost every thing chocked because of thread, increase in heap space was really slow. JVM bufer pool that was usually spiked in the similar fashion as thread count, and I saw massive loading and unloading of classes.
Thank you for all of your insights. This was really helpful. Clearly I was on the way to a disaster.
Do you think SharedFlows can be used as actor for this kind of pattern ?


04/29/2021, 9:27 AM
would probably work best for your use case @Satyam Agarwal

Satyam Agarwal

04/29/2021, 9:51 AM
Woh, I didn’t know about it. Will read up on it. Thank you so much


04/29/2021, 7:35 PM
Do we have example/snippet somewhere using best practice for fire/forget.