```suspend fun send(someId) { val currentState ...
# coroutines
u
Copy code
suspend fun send(someId) {
   val currentState = db.getState(someId)
   if (currentState == null) error("Unknown id")
   if (currentState == Sent) return // idempotent
   if (currentState == Sending) .. mutex?

   try {
      db.setState(Sending, someId)
      api.send(..)
      db.setState(Sent, someId)
   } catch (ex) {
      db.setState(Idle, someId)
   }
}
This is very common pattern in apps I make. What would the idiomatic way to make this code thread/coroutine safe? Obviously, if same id ist being sent concurrently multiple times, state might get smashed Is it okay to use Mutex around the whole function? Granted, only same ids needs to be serialized -- should I then have a Map<SomeId, Mutex>? Is there maybe some conditional Mutex? Or maybe not mutex at all, and use some sort of concurrent counter as not to revert to Idle when other coroutine is Sending etc? Or some Channel magic I dont know?
e
u
alright so a keyed mutex asbtraction, with referencequeue to avoid synchronization block, and weakreferences for entries, to avoid dealing with freeing the cache?
e
reference queue is to garbage collect dead references, but yeah. if you've got a fixed number of threads you might find it easier to just employ sharding,
Copy code
val mutexes = Array(Runtime.getRuntime().availableProcessors()) { Mutex() }
mutexes[Math.floorMod(someId.hashCode(), mutexes.size)].withLock { ... }
u
yea, actually its not very probably in my case that there will be concurrent same ids goin on, but yea it has to be handled to be corrent anyways, so its "cool" for coroutines to hold Mutex for relatively long times? I'm just trained by thread synchronization, to not hold locks long, and for sure not across network requests
e
coroutines are lighter-weight than threads so it's not as costly to have a lot waiting around… but still better not to block work if you can help it
u
yea, I think I read some instagram engineering blog post how they handle concurrent state smashing
okay its only tangentially related to my code