Is it okay to store data in the CoroutineContext s...
# coroutines
l
Is it okay to store data in the CoroutineContext so that we don’t have to pass it from suspend function to suspend function? The use case is that we have a backend application, and we currently store authentication information at the beginning of each request so that we are able to receive them from every suspend function without needing to pass them as paremeters all the time…
o
If parameters are too inconvenient, coroutine context elements are certainly an option. To access such state outside of suspend functions, you could also use `ThreadLocal.asContextElement()`: https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html#thread-local-data
However, the usual caveats of global-scope dependencies apply. In cases similar to the above, I usually have some sort of session object, which I pass around as a method or constructor parameter.
c
I store the authentication in the coroutine scope too. It's convenient for tests (it's very readable). Do note that if you have a class constructed with a scope, and write
Copy code
scope.launch { ... }
the context in the scope is not the caller's.
l
@Oliver.O What do you mean by “Caveat of global-scope dependendies”?
o
Code is much simpler to reason about with parameter passing. You can literally see where the data comes from. Once you have global state (or semi-global state with coroutine contexts or `ThreadLocal`s), data can come from anywhere as a side effect. While global state is sometimes convenient and can be pretty manageable on a smaller scale, many systems we build grow over time. At that point, comprehensibility suffers when we have webs of implicit interdependencies. See this thread on why Jim Sproch once said he regrets having introduced `CompositionLocal`s to Compose: https://twitter.com/JimSproch/status/1573034165406089216 That being said, every architectural decision depends on context, so this may not apply to your use-case. Does that make sense?
c
It is your decision whether hiding data in implicit contextual elements makes your project easier or harder to reason about. In my case, I decided that storing the user ID (and only that) in the coroutine context makes it easier to work on the project than having to pass it around everywhere, but it's most likely not going to fit all cases, and even then it's a single data point, there's no shared logic or anything. As Olivier said, it's a major decision to hide things like this, which can spectacularly backfire if you need to debug where data comes from.
m
Coroutine context is a suitable place to store metadata but probably not data that is used by a function for its purpose.
193 Views