Поскольку MongoDB не поддерживает транзакции, вы не можете безопасно установить пессимистическую блокировку для пакета элементов, если у вас нет отдельного документа для этого - подробнее об этом в конце.
Давайте начнемс запросом: Вы не можете запросить sth.как «где x + y < z
» в MongoDB.Вместо этого вам придется использовать поле для следующего срока оплаты, например, nextDue
:
{
"nextDue": "420",
"work": { ... }
}
Теперь каждый работник может получить пару элементов (ПРИМЕЧАНИЕ: это весь псевдокод, а неконкретный язык программирования):
var result = db.queue.find( { "nextDue": { $gt, startTime } }).limit(50);
// hint: you can do a random skip here to decrease the chances of collisions
// between workers.
foreach(rover in result)
{
// pessimistic locking: '-1' indicates this is in progress.
// I'd recommend a flag instead, however...
var currentItem = db.queue.findAndModify({ "_id" : rover.id, "nextDue" : {$gt, startTime}}, {$set : {"nextDue" : -1}});
if(currentItem == null)
continue; // hit a lock: another worker is processing this already
// ... process job ...
db.queue.findAndModify({ "_id" : rover.id, "nextDue" : "-1"}, {$set : {"nextDue" : yourNextDue }});
}
По сути, я вижу два метода пессимистической блокировки нескольких документов.Один из них - создать корзину для документов, которые вы пытаетесь заблокировать, поместить дескрипторы заданий в корзину и обработать эти корзины.Поскольку теперь контейнер представляет собой один объект, вы можете положиться на атомарные модификаторы.
Другой вариант - использовать двухфазное принятие , которое также создает другой объект для транзакции,но не требует, чтобы вы переместили ваши документы в другой документ.Однако это довольно сложный шаблон.
Псевдокод, который я представил выше, работал очень хорошо в двух приложениях, но в обоих приложениях отдельные задания выполнялись довольно долго (от полсекунды до нескольких часов).1017 *