Hi, I want to have something like Mutex (or like S...
# coroutines
n
Hi, I want to have something like Mutex (or like Sempahore with permits 1 action per certain key), but which is attached to certain value, for example entity id and don’t allow concurrent operations on the same entity. Id’ like to queue not all invocation but split them by some key (like entity id). Any ideas how to do that with Kotlin Coroutines 🙂 ?
Of course I can have map of Mutexes like: EntityId -> Mutex, but maybe someone knows more clever solution?
p
I recently achieved similar with a
MutableMap<EntityId, Job>
using
map.compute(key) { _, exist -> launch { exist?.join(); doWork() }
and a periodic
map.values.removeIf { it.isCompleted }
- wasn’t overly happy as I’m sure there’s a better way but it seems to do the job.
n
I understand and done it with Coffeine cache (instead of simple ConcurrentHashMap) which removes unused Mutexes. But looking for better solution if exists 🙂
Copy code
class MutexSerializedCommandHandler<C, R>(
    private val handler: CommandHandler<C, R>,
    private val keyProvider: (command: C) -> Any,
) : CommandHandler<C, R> {

    private val mutexCache: AsyncCache<Any, Mutex> = Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterAccess(Duration.ofSeconds(60))
        .buildAsync()


    override suspend fun handle(command: C): Result<R> = resultOf {
        val key = keyProvider(command)
        val keyMutex = mutexCache.get(key) { k -> Mutex() }.await()
        return keyMutex.withLock(key) { handler.handle(command) }
    }
}
t
Maybe you could use the actor pattern to solve your use case