I have a function
type Command struct {
id Uuid
}
handleCommand(cmd Command)
{
entity := lookupEntityInDataBase(cmd.Uuid)
entity.handleCommand(cmd)
saveEntityInDatabase(entity)
}
However this function can be called in parallel, and the entities are assumed to be non-threadsafe leading to racyness in the entity's state and the state which will be saved in the database.
A simple mutex locking at the beginning and end in this function would solve this, but would result in overly pessimistic synchronisation, since entities of different instances (i.e. different uuid), should be allowed to handle their commands in parallel.
An alternative can be to keep a Map of map[uuid]sync.Mutex
, and create a new mutex if a uuid is not encountered before, and create it in a threadsafe manner. However, this will result in a possibly endlessly growing map of all the uuids every encountered at runtime.
I thought of cleaning up the mutexes afterwards, but doing this threadsafe, and realising that another thread may already be waiting for the mutex opens so many cans of worms.
I hope I am missing a very simple and elegant solution.
The Moby project has such a thing as a library, see https://github.com/moby/locker
The one-line description is,
locker provides a mechanism for creating finer-grained locking to help free up more global locks to handle other tasks.