Skip to content

Commit

Permalink
[11.x] Allow SyncQueue to dispatch jobs after a transaction is comm…
Browse files Browse the repository at this point in the history
…itted (#48860)

* Fix after commit jobs using the sync queue

* Additional test

* Remove unnecessary check

* formatting

---------

Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
mateusjatenee and taylorotwell authored Nov 1, 2023
1 parent 2acb803 commit 444141b
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Illuminate/Queue/Queue.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ function () use ($payload, $queue, $delay, $callback, $job) {
*/
protected function shouldDispatchAfterCommit($job)
{
if (is_object($job) && $job instanceof ShouldQueueAfterCommit) {
if ($job instanceof ShouldQueueAfterCommit) {
return true;
}

Expand Down
22 changes: 22 additions & 0 deletions src/Illuminate/Queue/SyncQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ public function size($queue = null)
* @throws \Throwable
*/
public function push($job, $data = '', $queue = null)
{
if ($this->shouldDispatchAfterCommit($job) &&
$this->container->bound('db.transactions')) {
return $this->container->make('db.transactions')->addCallback(
fn () => $this->executeJob($job, $data, $queue)
);
}

return $this->executeJob($job, $data, $queue);
}

/**
* Execute a given job synchronously.
*
* @param string $job
* @param mixed $data
* @param string|null $queue
* @return int
*
* @throws \Throwable
*/
protected function executeJob($job, $data = '', $queue = null)
{
$queueJob = $this->resolveJob($this->createPayload($job, $queue, $data), $queue);

Expand Down
48 changes: 48 additions & 0 deletions tests/Queue/QueueSyncQueueTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Queue\QueueableEntity;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;
use Illuminate\Database\DatabaseTransactionsManager;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Jobs\SyncJob;
use Illuminate\Queue\SyncQueue;
Expand Down Expand Up @@ -77,6 +79,32 @@ public function testCreatesPayloadObject()
$this->assertSame('extraValue', $e->getMessage());
}
}

public function testItAddsATransactionCallbackForAfterCommitJobs()
{
$sync = new SyncQueue;
$container = new Container;
$container->bind(\Illuminate\Contracts\Container\Container::class, \Illuminate\Container\Container::class);
$transactionManager = m::mock(DatabaseTransactionsManager::class);
$transactionManager->shouldReceive('addCallback')->once()->andReturn(null);
$container->instance('db.transactions', $transactionManager);

$sync->setContainer($container);
$sync->push(new SyncQueueAfterCommitJob());
}

public function testItAddsATransactionCallbackForInterfaceBasedAfterCommitJobs()
{
$sync = new SyncQueue;
$container = new Container;
$container->bind(\Illuminate\Contracts\Container\Container::class, \Illuminate\Container\Container::class);
$transactionManager = m::mock(DatabaseTransactionsManager::class);
$transactionManager->shouldReceive('addCallback')->once()->andReturn(null);
$container->instance('db.transactions', $transactionManager);

$sync->setContainer($container);
$sync->push(new SyncQueueAfterCommitInterfaceJob());
}
}

class SyncQueueTestEntity implements QueueableEntity
Expand Down Expand Up @@ -134,3 +162,23 @@ public function getValueFromJob($key)
return $payload['data'][$key] ?? null;
}
}

class SyncQueueAfterCommitJob
{
use InteractsWithQueue;

public $afterCommit = true;

public function handle()
{
}
}

class SyncQueueAfterCommitInterfaceJob implements ShouldQueueAfterCommit
{
use InteractsWithQueue;

public function handle()
{
}
}

0 comments on commit 444141b

Please sign in to comment.