Reputation: 939
I have a task worker written in Java and using a MongoDB 3.4 replica set that runs many threads each doing essentially this.
As you may be able to see, there is a race condition here; multiple tasks can all finish at about the same time and think that they are the last task to complete. I want to use MongoDB to make sure only one of those tasks is allowed to start the next stage of processing.
I have the following code that is meant to ensure that only one of those tasks can continue (I'm using Jongo to interface with MongoDB).
Chipset modified = chipsets
.findAndModify("{_id: #, status: {$ne: #}}", new Object[] { chipset.getId(), Chipset.Status.Queued })
.with("{$set: {status: #}}", new Object[] { Chipset.Status.Queued })
.returnNew().as(Chipset.class);
if (modified != null)
runNextProcessingStep();
Pretty simple here; I'm just using findAndModify to change the status of the Chipset (set of tasks) to Queued. The one that successfully makes the change gets to execute runNextProcessingStep().
Or that's how I think it should work. In reality, several tasks, even ones that finish 2 seconds apart, are somehow getting back a non-null modified
. As I understand it MongoDB should be locking the document when running findAndModify so that a non-null document can be returned no more than once.
I've read Linearizable Reads via findAndModify and have implemented everything said in there. I've set the connection write concern to Majority and the read concern to Linearizable. I've created a unique composite index on _id and status. Still nothing. Perhaps I have misunderstood how findAndModify actually behaves? What am I doing wrong?
Upvotes: 5
Views: 901
Reputation: 939
Well, this is embarrassing but in the interest of being a good internet citizen I'll update this with what happened. There was another thread that was changing statuses out from under me. I had convinced myself this couldn't be the case but, well, concurrency can be a real pain sometimes. findAndModify works exactly how I thought it should.
Upvotes: 1