I have a working task written in Java and using the MongoDB 3.4 replica set that launches many threads, each of which does this essentially.
- Run task
- Signal of completion of this task by updating the document for this task in MongoDB
- Run a query to check if all tasks in this task set are completed
- If yes, proceed to the next processing step.
- Otherwise do nothing
As you can see, there is a race condition; several tasks may end at about the same time and think that they are the last task to complete. I want to use MongoDB to make sure that only one of these tasks allows us to start the next processing step.
I have the following code designed to continue only one of these tasks (I use Jongo to interact 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 just use findAndModify to change the chipset status (task set) to Queued. The one that makes the change successfully gets runNextProcessingStep () done.
Or, as I think it should work. In fact, several tasks, even those that end at a distance of 2 seconds, somehow return a nonzero value modified. As far as I understand, MongoDB should block the document when findAndModify starts, so that a non-empty document can be returned no more than once.
findAndModify . Linearizable. _id status. . , , findAndModify? ?