Now my question is: what if I want to have a long ...
# coroutines
c
Now my question is: what if I want to have a long term cache? For example a UserRepository. I can query the Repository for the user that belongs to a specific ID. What I want is that this Repository would save the users that are requested and saves them for some time. I know how to do that with synchronisation primitives, with shared mutable states, but that's the opposite of the coroutines mentality. How would you do that with coroutines?
1
g
You can do this with coroutines, you can use
async
as the simplest way to create Deferred that encapsulate some value and provides suspend function to access it If you need something more complicated than a Map with Deffered, you can use the same approach with sync primivies, just use their suspend counterpart: Mutex and Semaphore from kotlinx.coroutines
c
I don't understand... Do you mean I should defer the cache? I don't understand how that can help
g
See, Deffered is just a suspendable Promise
It can be used exactly for this: request and cache resulting value, you just have to cache this Deffered itself.
The simplest possible implementation is:
Copy code
val cache: MutableMap<String, Deferred<User>>
suspend fun loadUser(id: String): User {
  // Get existing deferred or create new one
  val deferred = cache.getOrPut(id) { 
    async { 
      storage.loadUser(id)
    }
  }
  // I prefer use suspend function, but you can just return deferred if you want
   return deferred.await()
}
Of course you still need some.way to make cache map somehow thread safe, you can use Java concurrent map or use Mutex from kotlinx.coroutines,or more sophisticated solution based on actor or just by switching to single thread that manages this map
c
Ohh I understand what you mean My question was more about "what strategy should I use to avoid sharing mutable state" rather than "what can I use to structure my cache" The talk explained how a set that is used for short time caching should be within the scope of the actor so that it is not shared; I was wondering how to modify that pattern to have a cache that starts when the application starts and ends at the same time of the application. Maybe just a single coroutine that includes the MutableMap and communicates via Channels, and ran in the GlobalScope would be enough?
g
Yes, single coroutine with channel for communication is
actor
and part of kotlinx.coroutines. for sure you can run it in GlobalScope (or just create own ApplicationScope with app lifecycle, if you want be explicit)