Reputation: 1312
I have multiple servers sharing a common mongodb. In the DB there is a list of jobs, the servers have to finish. As I want to divide the load over all servers and want to avoid multiple servers doing the same job, I want to "Lock" that job.
My Idea is:
Set the element as taken if it is not yet taken:
db.collection.update({done: false, taken: false},{$set: {taken: true, takenBy: myIp}});
Check if the server got the mutex on this element: db.collection.findOne({taken: true, takenBy: myIp})
Would that be the best way to "synchronize" multiple worker servers over a mongodb (does the server do updates in a single transaction like mysql) or could the server do multiple of this first commands at once?
Upvotes: 2
Views: 5789
Reputation: 312085
The key MongoDB feature in this area is that an update to a single document is atomic. From the docs:
In MongoDB, a write operation is atomic on the level of a single document, even if the operation modifies multiple embedded documents within a single document.
When a single write operation modifies multiple documents, the modification of each document is atomic, but the operation as a whole is not atomic and other operations may interleave. However, you can isolate a single write operation that affects multiple documents using the
$isolated
operator.
So for your update of:
db.collection.update({done: false, taken: false},{$set: {taken: true, takenBy: myIp}});
this means that it will atomically find a doc that matches the criteria and then update it. So yes, that will work well to assign a task to a given server.
See this other post for more details on implementing a shared work queue in MongoDB. A key point that's mentioned there is the use of findAndModify
to both perform the update and return the updated doc.
Upvotes: 4