Commit 9d32ae68 authored by Fady Khalife's avatar Fady Khalife

Fixes #743 for version 3.x

parent e1c12ac0
...@@ -2,31 +2,78 @@ ...@@ -2,31 +2,78 @@
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Queue\DatabaseQueue; use Illuminate\Queue\DatabaseQueue;
use Illuminate\Queue\Jobs\DatabaseJob;
use MongoDB\Operation\FindOneAndUpdate;
use DB;
class MongoQueue extends DatabaseQueue class MongoQueue extends DatabaseQueue
{ {
/** /**
* Get the next available job for the queue. * Pop the next job off of the queue.
*
* @param string $queue
*
* @return \Illuminate\Contracts\Queue\Job|null
*/
public function pop($queue = null)
{
$queue = $this->getQueue($queue);
if (!is_null($this->expire))
{
$this->releaseJobsThatHaveBeenReservedTooLong($queue);
}
if ($job = $this->getNextAvailableJobAndReserve($queue))
{
return new DatabaseJob(
$this->container, $this, $job, $queue
);
}
}
/**
* Get the next available job for the queue and mark it as reserved.
*
* When using multiple daemon queue listeners to process jobs there
* is a possibility that multiple processes can end up reading the
* same record before one has flagged it as reserved.
*
* This race condition can result in random jobs being run more then
* once. To solve this we use findOneAndUpdate to lock the next jobs
* record while flagging it as reserved at the same time.
* *
* @param string|null $queue * @param string|null $queue
*
* @return \StdClass|null * @return \StdClass|null
*/ */
protected function getNextAvailableJob($queue) protected function getNextAvailableJobAndReserve($queue)
{ {
$job = $this->database->table($this->table) $job = DB::getCollection($this->table)->findOneAndUpdate(
->lockForUpdate() [
->where('queue', $this->getQueue($queue)) 'queue' => $this->getQueue($queue),
->where('reserved', 0) 'reserved' => 0,
->where('available_at', '<=', $this->getTime()) 'available_at' => ['$lte' => $this->getTime()],
->orderBy('id', 'asc')
->first();
if ($job) { ],
$job = (object) $job; [
'$set' => [
'reserved' => 1,
'reserved_at' => $this->getTime(),
],
],
[
'returnNewDocument ' => true,
'sort' => ['available_at' => 1],
]
);
if ($job)
{
$job->id = $job->_id; $job->id = $job->_id;
} }
return $job ?: null; return $job;
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment