2

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?

Community
  • 1
  • 1
Tobi
  • 1,175
  • 1
  • 19
  • 44
  • 1
    Possible dupe of http://stackoverflow.com/questions/9274777/mongodb-as-a-queue-service – JohnnyHK Sep 23 '15 at 01:00
  • This question is more about how mongodb encapsulates single queries and updates (in sql they are called transactions) not about how to build a queue (even when it is the goal to build a queue and that was the reason for the question, I want to know how mongod works under the hood) – Tobi Sep 24 '15 at 12:53
  • 1
    The short answer is that all updates to a single document are atomic. Have you seen http://docs.mongodb.org/manual/core/write-operations-atomicity/? – JohnnyHK Sep 24 '15 at 12:57
  • Thanks, if you write this as an answer, you get an upvote, I searched for transactions but that probably was the wrong wording. – Tobi Sep 24 '15 at 13:04

1 Answers1

4

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.

Community
  • 1
  • 1
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471