diff --git a/src/Illuminate/Broadcasting/BroadcastEvent.php b/src/Illuminate/Broadcasting/BroadcastEvent.php index 775df78059d7..da8c374a234c 100644 --- a/src/Illuminate/Broadcasting/BroadcastEvent.php +++ b/src/Illuminate/Broadcasting/BroadcastEvent.php @@ -46,6 +46,7 @@ public function __construct($event) $this->event = $event; $this->tries = property_exists($event, 'tries') ? $event->tries : null; $this->timeout = property_exists($event, 'timeout') ? $event->timeout : null; + $this->dispatchAfterTransactions = property_exists($event, 'dispatchAfterTransactions') ? $event->dispatchAfterTransactions : null; } /** diff --git a/src/Illuminate/Bus/Queueable.php b/src/Illuminate/Bus/Queueable.php index c2520b98c040..0591edf519cc 100644 --- a/src/Illuminate/Bus/Queueable.php +++ b/src/Illuminate/Bus/Queueable.php @@ -52,6 +52,13 @@ trait Queueable */ public $delay; + /** + * Indicate the job should be dispatched after database transactions. + * + * @var bool|null + */ + public $dispatchAfterTransactions; + /** * The middleware the job should be dispatched through. * @@ -133,6 +140,19 @@ public function delay($delay) return $this; } + /** + * Indicate that the job should be dispatched after database transactions. + * + * @param bool|null $value + * @return $this + */ + public function afterTransactions($value = true) + { + $this->dispatchAfterTransactions = $value; + + return $this; + } + /** * Specify the middleware the job should be dispatched through. * diff --git a/src/Illuminate/Database/Concerns/ManagesTransactions.php b/src/Illuminate/Database/Concerns/ManagesTransactions.php index 1dd4475290d6..995c7e438621 100644 --- a/src/Illuminate/Database/Concerns/ManagesTransactions.php +++ b/src/Illuminate/Database/Concerns/ManagesTransactions.php @@ -44,7 +44,7 @@ public function transaction(Closure $callback, $attempts = 1) $this->getPdo()->commit(); } - $this->transactions = max(0, $this->transactions - 1); + $this->decrementTransactionsCount(); } catch (Throwable $e) { $this->handleCommitTransactionException( $e, $currentAttempt, $attempts @@ -76,7 +76,7 @@ protected function handleTransactionException(Throwable $e, $currentAttempt, $ma // let the developer handle it in another way. We will decrement too. if ($this->causedByConcurrencyError($e) && $this->transactions > 1) { - $this->transactions--; + $this->decrementTransactionsCount(); throw $e; } @@ -105,7 +105,7 @@ public function beginTransaction() { $this->createTransaction(); - $this->transactions++; + $this->incrementTransactionsCount(); $this->fireConnectionEvent('beganTransaction'); } @@ -178,7 +178,7 @@ public function commit() $this->getPdo()->commit(); } - $this->transactions = max(0, $this->transactions - 1); + $this->decrementTransactionsCount(); $this->fireConnectionEvent('committed'); } @@ -195,7 +195,7 @@ public function commit() */ protected function handleCommitTransactionException(Throwable $e, $currentAttempt, $maxAttempts) { - $this->transactions = max(0, $this->transactions - 1); + $this->decrementTransactionsCount(); if ($this->causedByConcurrencyError($e) && $currentAttempt < $maxAttempts) { @@ -203,7 +203,7 @@ protected function handleCommitTransactionException(Throwable $e, $currentAttemp } if ($this->causedByLostConnection($e)) { - $this->transactions = 0; + $this->updateTransactionsCount(0); } throw $e; @@ -239,7 +239,7 @@ public function rollBack($toLevel = null) $this->handleRollBackException($e); } - $this->transactions = $toLevel; + $this->updateTransactionsCount($toLevel); $this->fireConnectionEvent('rollingBack'); } @@ -274,7 +274,7 @@ protected function performRollBack($toLevel) protected function handleRollBackException(Throwable $e) { if ($this->causedByLostConnection($e)) { - $this->transactions = 0; + $this->updateTransactionsCount(0); } throw $e; @@ -289,4 +289,63 @@ public function transactionLevel() { return $this->transactions; } + + /** + * Increment the number of transactions. + * + * @return void + */ + protected function incrementTransactionsCount() + { + $this->transactions++; + + static::$totalTransactions++; + } + + /** + * Decrement the number of transactions. + * + * @return void + */ + protected function decrementTransactionsCount() + { + $this->transactions = max(0, $this->transactions - 1); + + static::$totalTransactions = max(0, static::$totalTransactions - 1); + + if (static::$totalTransactions == 0) { + $this->callAfterTransactionCallbacks(); + } + } + + /** + * Update the number of transactions. + * + * @param int $count + * @return void + */ + protected function updateTransactionsCount($count) + { + static::$totalTransactions = static::$totalTransactions + $count - $this->transactions; + + $this->transactions = $count; + + if (static::$totalTransactions == 0) { + $this->callAfterTransactionCallbacks(); + } + } + + /** + * Execute the after transaction callbacks. + * + * @return void + */ + protected function callAfterTransactionCallbacks() + { + foreach (static::$afterTransactionCallbacks as $callback) { + call_user_func($callback); + } + + static::$afterTransactionCallbacks = []; + } } diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 98f12639713e..be903f5ac216 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -112,6 +112,20 @@ class Connection implements ConnectionInterface */ protected $transactions = 0; + /** + * The total number of active transactions. + * + * @var int + */ + public static $totalTransactions = 0; + + /** + * The callbacks to invoke after transactions. + * + * @var callable[] + */ + public static $afterTransactionCallbacks = []; + /** * Indicates if changes have been made to the database. * diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index 91214b457188..18091f9a35e9 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -559,6 +559,7 @@ protected function propagateListenerOptions($listener, $job) $job->timeout = $listener->timeout ?? null; $job->retryUntil = method_exists($listener, 'retryUntil') ? $listener->retryUntil() : null; + $job->dispatchAfterTransactions = $listener->dispatchAfterTransactions ?? null; }); } diff --git a/src/Illuminate/Foundation/Bus/PendingDispatch.php b/src/Illuminate/Foundation/Bus/PendingDispatch.php index 9495dc15c114..55afb84ec1dd 100644 --- a/src/Illuminate/Foundation/Bus/PendingDispatch.php +++ b/src/Illuminate/Foundation/Bus/PendingDispatch.php @@ -99,6 +99,19 @@ public function delay($delay) return $this; } + /** + * Indicate that the job should be dispatched after database transactions. + * + * @param bool|null $value + * @return $this + */ + public function afterTransactions($value = true) + { + $this->job->afterTransactions($value); + + return $this; + } + /** * Set the jobs that should run if this job is successful. * diff --git a/src/Illuminate/Mail/SendQueuedMailable.php b/src/Illuminate/Mail/SendQueuedMailable.php index 76822bcd05f5..8f579a78e3ee 100644 --- a/src/Illuminate/Mail/SendQueuedMailable.php +++ b/src/Illuminate/Mail/SendQueuedMailable.php @@ -39,6 +39,7 @@ public function __construct(MailableContract $mailable) $this->mailable = $mailable; $this->tries = property_exists($mailable, 'tries') ? $mailable->tries : null; $this->timeout = property_exists($mailable, 'timeout') ? $mailable->timeout : null; + $this->dispatchAfterTransactions = property_exists($mailable, 'dispatchAfterTransactions') ? $mailable->dispatchAfterTransactions : null; } /** diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index 98fb2fe56d9a..2558e15e39e6 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -206,6 +206,7 @@ protected function queueNotification($notifiables, $notification) ($notification->delay[$channel] ?? null) : $notification->delay ) + ->afterTransactions($notification->dispatchAfterTransactions) ->through( array_merge( method_exists($notification, 'middleware') ? $notification->middleware() : [], diff --git a/src/Illuminate/Queue/BeanstalkdQueue.php b/src/Illuminate/Queue/BeanstalkdQueue.php index 49c36bdac07f..30e773b51645 100755 --- a/src/Illuminate/Queue/BeanstalkdQueue.php +++ b/src/Illuminate/Queue/BeanstalkdQueue.php @@ -37,6 +37,13 @@ class BeanstalkdQueue extends Queue implements QueueContract */ protected $blockFor; + /** + * Indicate that pushes should be delayed till after database transactions commit. + * + * @var bool + */ + protected $dispatchAfterTransactions = false; + /** * Create a new Beanstalkd queue instance. * @@ -44,14 +51,20 @@ class BeanstalkdQueue extends Queue implements QueueContract * @param string $default * @param int $timeToRun * @param int $blockFor + * @param bool $dispatchAfterTransactions * @return void */ - public function __construct(Pheanstalk $pheanstalk, $default, $timeToRun, $blockFor = 0) + public function __construct(Pheanstalk $pheanstalk, + $default, + $timeToRun, + $blockFor = 0, + $dispatchAfterTransactions = false) { $this->default = $default; $this->blockFor = $blockFor; $this->timeToRun = $timeToRun; $this->pheanstalk = $pheanstalk; + $this->dispatchAfterTransactions = $dispatchAfterTransactions; } /** @@ -77,7 +90,11 @@ public function size($queue = null) */ public function push($job, $data = '', $queue = null) { - return $this->pushRaw($this->createPayload($job, $this->getQueue($queue), $data), $queue); + $payload = $this->createPayload($job, $this->getQueue($queue), $data); + + return $this->enqueueUsing($this, $job, function () use ($payload, $queue) { + return $this->pushRaw($payload, $queue); + }); } /** @@ -106,14 +123,16 @@ public function pushRaw($payload, $queue = null, array $options = []) */ public function later($delay, $job, $data = '', $queue = null) { - $pheanstalk = $this->pheanstalk->useTube($this->getQueue($queue)); - - return $pheanstalk->put( - $this->createPayload($job, $this->getQueue($queue), $data), - Pheanstalk::DEFAULT_PRIORITY, - $this->secondsUntil($delay), - $this->timeToRun - ); + return $this->enqueueUsing($this, $job, function () use ($delay, $job, $data, $queue) { + $pheanstalk = $this->pheanstalk->useTube($this->getQueue($queue)); + + return $pheanstalk->put( + $this->createPayload($job, $this->getQueue($queue), $data), + Pheanstalk::DEFAULT_PRIORITY, + $this->secondsUntil($delay), + $this->timeToRun + ); + }); } /** diff --git a/src/Illuminate/Queue/Connectors/BeanstalkdConnector.php b/src/Illuminate/Queue/Connectors/BeanstalkdConnector.php index b54d80193b69..f38e5b67a519 100755 --- a/src/Illuminate/Queue/Connectors/BeanstalkdConnector.php +++ b/src/Illuminate/Queue/Connectors/BeanstalkdConnector.php @@ -20,7 +20,8 @@ public function connect(array $config) $this->pheanstalk($config), $config['queue'], $config['retry_after'] ?? Pheanstalk::DEFAULT_TTR, - $config['block_for'] ?? 0 + $config['block_for'] ?? 0, + $config['after_commits'] ?? false ); } diff --git a/src/Illuminate/Queue/Connectors/DatabaseConnector.php b/src/Illuminate/Queue/Connectors/DatabaseConnector.php index 893a898f6b66..71cbdcadf1c1 100644 --- a/src/Illuminate/Queue/Connectors/DatabaseConnector.php +++ b/src/Illuminate/Queue/Connectors/DatabaseConnector.php @@ -37,7 +37,8 @@ public function connect(array $config) $this->connections->connection($config['connection'] ?? null), $config['table'], $config['queue'], - $config['retry_after'] ?? 60 + $config['retry_after'] ?? 60, + $config['after_commits'] ?? false ); } } diff --git a/src/Illuminate/Queue/Connectors/RedisConnector.php b/src/Illuminate/Queue/Connectors/RedisConnector.php index 1efe5f65e903..a1b6e32ec6d8 100644 --- a/src/Illuminate/Queue/Connectors/RedisConnector.php +++ b/src/Illuminate/Queue/Connectors/RedisConnector.php @@ -46,7 +46,8 @@ public function connect(array $config) $this->redis, $config['queue'], $config['connection'] ?? $this->connection, $config['retry_after'] ?? 60, - $config['block_for'] ?? null + $config['block_for'] ?? null, + $config['after_commits'] ?? false ); } } diff --git a/src/Illuminate/Queue/Connectors/SqsConnector.php b/src/Illuminate/Queue/Connectors/SqsConnector.php index 07d7f8232674..ca392bf360dc 100755 --- a/src/Illuminate/Queue/Connectors/SqsConnector.php +++ b/src/Illuminate/Queue/Connectors/SqsConnector.php @@ -23,7 +23,11 @@ public function connect(array $config) } return new SqsQueue( - new SqsClient($config), $config['queue'], $config['prefix'] ?? '', $config['suffix'] ?? '' + new SqsClient($config), + $config['queue'], + $config['prefix'] ?? '', + $config['suffix'] ?? '', + $config['after_commits'] ?? false ); } diff --git a/src/Illuminate/Queue/DatabaseQueue.php b/src/Illuminate/Queue/DatabaseQueue.php index 89fb91cb3038..af08302ecd98 100644 --- a/src/Illuminate/Queue/DatabaseQueue.php +++ b/src/Illuminate/Queue/DatabaseQueue.php @@ -40,6 +40,13 @@ class DatabaseQueue extends Queue implements QueueContract, ClearableQueue */ protected $retryAfter = 60; + /** + * Indicate that pushes should be delayed till after database transactions commit. + * + * @var bool + */ + protected $dispatchAfterTransactions = false; + /** * Create a new database queue instance. * @@ -47,14 +54,20 @@ class DatabaseQueue extends Queue implements QueueContract, ClearableQueue * @param string $table * @param string $default * @param int $retryAfter + * @param bool $dispatchAfterTransactions * @return void */ - public function __construct(Connection $database, $table, $default = 'default', $retryAfter = 60) + public function __construct(Connection $database, + $table, + $default = 'default', + $retryAfter = 60, + $dispatchAfterTransactions = false) { $this->table = $table; $this->default = $default; $this->database = $database; $this->retryAfter = $retryAfter; + $this->dispatchAfterTransactions = $dispatchAfterTransactions; } /** @@ -80,9 +93,11 @@ public function size($queue = null) */ public function push($job, $data = '', $queue = null) { - return $this->pushToDatabase($queue, $this->createPayload( - $job, $this->getQueue($queue), $data - )); + $payload = $this->createPayload($job, $this->getQueue($queue), $data); + + return $this->enqueueUsing($this, $job, function () use ($queue, $payload) { + return $this->pushToDatabase($queue, $payload); + }); } /** @@ -109,9 +124,11 @@ public function pushRaw($payload, $queue = null, array $options = []) */ public function later($delay, $job, $data = '', $queue = null) { - return $this->pushToDatabase($queue, $this->createPayload( - $job, $this->getQueue($queue), $data - ), $delay); + $payload = $this->createPayload($job, $this->getQueue($queue), $data); + + return $this->enqueueUsing($this, $job, function () use ($queue, $delay, $payload) { + return $this->pushToDatabase($queue, $payload, $delay); + }); } /** diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index e9a98c663869..83faa2dc8b60 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -5,6 +5,7 @@ use Closure; use DateTimeInterface; use Illuminate\Container\Container; +use Illuminate\Database\Connection; use Illuminate\Support\InteractsWithTime; use Illuminate\Support\Str; @@ -255,6 +256,28 @@ protected function withCreatePayloadHooks($queue, array $payload) return $payload; } + /** + * Enqueue a jobs using the given callback. + * + * @param \Illuminate\Contracts\Queue\Queue $connection + * @param \Closure|string|object $job + * @param callable $callback + * @return mixed + */ + protected function enqueueUsing($connection, $job, $callback) + { + if (Connection::$totalTransactions > 0 && + $this->shouldDispatchAfterTransactions($connection, $job)) { + Connection::$afterTransactionCallbacks[] = function () use ($callback) { + $callback(); + }; + + return; + } + + return $callback(); + } + /** * Get the connection name for the queue. * @@ -288,4 +311,24 @@ public function setContainer(Container $container) { $this->container = $container; } + + /** + * Determine if the job should be dispatched after database transactions. + * + * @param \Illuminate\Contracts\Queue\Queue $connection + * @param \Closure|string|object $job + * @return bool + */ + protected function shouldDispatchAfterTransactions($connection, $job) + { + if (is_object($job) && isset($job->dispatchAfterTransactions)) { + return $job->dispatchAfterTransactions; + } + + if (isset($connection->dispatchAfterTransactions)) { + return $connection->dispatchAfterTransactions; + } + + return false; + } } diff --git a/src/Illuminate/Queue/RedisQueue.php b/src/Illuminate/Queue/RedisQueue.php index 19fc07589497..1260f7b5a43b 100644 --- a/src/Illuminate/Queue/RedisQueue.php +++ b/src/Illuminate/Queue/RedisQueue.php @@ -5,6 +5,7 @@ use Illuminate\Contracts\Queue\ClearableQueue; use Illuminate\Contracts\Queue\Queue as QueueContract; use Illuminate\Contracts\Redis\Factory as Redis; +use Illuminate\Database\Connection; use Illuminate\Queue\Jobs\RedisJob; use Illuminate\Support\Str; @@ -45,6 +46,13 @@ class RedisQueue extends Queue implements QueueContract, ClearableQueue */ protected $blockFor = null; + /** + * Indicate that pushes should be delayed till after database transactions commit. + * + * @var bool + */ + protected $dispatchAfterTransactions = false; + /** * Create a new Redis queue instance. * @@ -53,15 +61,22 @@ class RedisQueue extends Queue implements QueueContract, ClearableQueue * @param string|null $connection * @param int $retryAfter * @param int|null $blockFor + * @param bool $dispatchAfterTransactions * @return void */ - public function __construct(Redis $redis, $default = 'default', $connection = null, $retryAfter = 60, $blockFor = null) + public function __construct(Redis $redis, + $default = 'default', + $connection = null, + $retryAfter = 60, + $blockFor = null, + $dispatchAfterTransactions = false) { $this->redis = $redis; $this->default = $default; $this->blockFor = $blockFor; $this->connection = $connection; $this->retryAfter = $retryAfter; + $this->dispatchAfterTransactions = $dispatchAfterTransactions; } /** @@ -108,7 +123,11 @@ public function bulk($jobs, $data = '', $queue = null) */ public function push($job, $data = '', $queue = null) { - return $this->pushRaw($this->createPayload($job, $this->getQueue($queue), $data), $queue); + $payload = $this->createPayload($job, $this->getQueue($queue), $data); + + return $this->enqueueUsing($this, $job, function () use ($payload, $queue) { + return $this->pushRaw($payload, $queue); + }); } /** @@ -140,7 +159,11 @@ public function pushRaw($payload, $queue = null, array $options = []) */ public function later($delay, $job, $data = '', $queue = null) { - return $this->laterRaw($delay, $this->createPayload($job, $this->getQueue($queue), $data), $queue); + $payload = $this->createPayload($job, $this->getQueue($queue), $data); + + return $this->enqueueUsing($this, $job, function () use ($payload, $delay, $queue) { + return $this->laterRaw($delay, $payload, $queue); + }); } /** diff --git a/src/Illuminate/Queue/SqsQueue.php b/src/Illuminate/Queue/SqsQueue.php index 8ec5fd110b45..3ad59fc7409b 100755 --- a/src/Illuminate/Queue/SqsQueue.php +++ b/src/Illuminate/Queue/SqsQueue.php @@ -38,6 +38,13 @@ class SqsQueue extends Queue implements QueueContract, ClearableQueue */ private $suffix; + /** + * Indicate that pushes should be delayed till after database transactions commit. + * + * @var bool + */ + protected $dispatchAfterTransactions = false; + /** * Create a new Amazon SQS queue instance. * @@ -45,14 +52,20 @@ class SqsQueue extends Queue implements QueueContract, ClearableQueue * @param string $default * @param string $prefix * @param string $suffix + * @param bool $dispatchAfterTransactions * @return void */ - public function __construct(SqsClient $sqs, $default, $prefix = '', $suffix = '') + public function __construct(SqsClient $sqs, + $default, + $prefix = '', + $suffix = '', + $dispatchAfterTransactions = false) { $this->sqs = $sqs; $this->prefix = $prefix; $this->default = $default; $this->suffix = $suffix; + $this->dispatchAfterTransactions = $dispatchAfterTransactions; } /** @@ -83,7 +96,11 @@ public function size($queue = null) */ public function push($job, $data = '', $queue = null) { - return $this->pushRaw($this->createPayload($job, $queue ?: $this->default, $data), $queue); + $payload = $this->createPayload($job, $queue ?: $this->default, $data); + + return $this->enqueueUsing($this, $job, function () use ($payload, $queue) { + return $this->pushRaw($payload, $queue); + }); } /** @@ -112,11 +129,13 @@ public function pushRaw($payload, $queue = null, array $options = []) */ public function later($delay, $job, $data = '', $queue = null) { - return $this->sqs->sendMessage([ - 'QueueUrl' => $this->getQueue($queue), - 'MessageBody' => $this->createPayload($job, $queue ?: $this->default, $data), - 'DelaySeconds' => $this->secondsUntil($delay), - ])->get('MessageId'); + return $this->enqueueUsing($this, $job, function () use ($data, $delay, $job, $queue) { + return $this->sqs->sendMessage([ + 'QueueUrl' => $this->getQueue($queue), + 'MessageBody' => $this->createPayload($job, $queue ?: $this->default, $data), + 'DelaySeconds' => $this->secondsUntil($delay), + ])->get('MessageId'); + }); } /** diff --git a/tests/Database/DatabaseConnectionTest.php b/tests/Database/DatabaseConnectionTest.php index 2be19458ed62..5d452fb69eee 100755 --- a/tests/Database/DatabaseConnectionTest.php +++ b/tests/Database/DatabaseConnectionTest.php @@ -29,6 +29,8 @@ class DatabaseConnectionTest extends TestCase protected function tearDown(): void { m::close(); + + Connection::$afterTransactionCallbacks = []; } public function testSettingDefaultCallsGetDefaultGrammar() @@ -425,6 +427,42 @@ public function testSchemaBuilderCanBeCreated() $this->assertSame($connection, $schema->getConnection()); } + public function testTotalTransactionsIsUpdated() + { + $pdo = $this->createMock(DatabaseConnectionTestMockPDO::class); + $connection = $this->getMockConnection([], $pdo); + + $connection::$totalTransactions = 0; + + $connection->beginTransaction(); + $this->assertEquals(1, $connection::$totalTransactions); + + $connection->commit(); + $this->assertEquals(0, $connection::$totalTransactions); + } + + public function testAfterTransactionCallbacksAreCalled() + { + $pdo = $this->createMock(DatabaseConnectionTestMockPDO::class); + $connection = $this->getMockConnection([], $pdo); + + $connection::$totalTransactions = 0; + + $name = 'mohamed'; + + $connection->beginTransaction(); + + Connection::$afterTransactionCallbacks[] = function () use (&$name) { + $name = 'zain'; + }; + + $this->assertEquals('mohamed', $name); + + $connection->commit(); + + $this->assertEquals('zain', $name); + } + protected function getMockConnection($methods = [], $pdo = null) { $pdo = $pdo ?: new DatabaseConnectionTestMockPDO; diff --git a/tests/Integration/Queue/QueueConnectionTest.php b/tests/Integration/Queue/QueueConnectionTest.php new file mode 100644 index 000000000000..83a6c38527e3 --- /dev/null +++ b/tests/Integration/Queue/QueueConnectionTest.php @@ -0,0 +1,53 @@ +set('app.debug', 'true'); + $app['config']->set('queue.default', 'sqs'); + $app['config']->set('queue.connections.sqs.after_commits', true); + } + + protected function tearDown(): void + { + QueueConnectionTestJob::$ran = false; + Connection::$totalTransactions; + Connection::$afterTransactionCallbacks = []; + } + + public function testJobWontGetDispatchedInsideATransaction() + { + Connection::$totalTransactions = 1; + + Bus::dispatch(new QueueConnectionTestJob); + Bus::dispatch(new QueueConnectionTestJob); + + $this->assertFalse(QueueConnectionTestJob::$ran); + $this->assertCount(2, Connection::$afterTransactionCallbacks); + } +} + +class QueueConnectionTestJob implements ShouldQueue +{ + use Dispatchable, Queueable; + + public static $ran = false; + + public function handle() + { + static::$ran = true; + } +} diff --git a/tests/Queue/QueueBeanstalkdQueueTest.php b/tests/Queue/QueueBeanstalkdQueueTest.php index 7134917a2369..1d65da6a1050 100755 --- a/tests/Queue/QueueBeanstalkdQueueTest.php +++ b/tests/Queue/QueueBeanstalkdQueueTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Queue; use Illuminate\Container\Container; +use Illuminate\Database\Connection; use Illuminate\Queue\BeanstalkdQueue; use Illuminate\Queue\Jobs\BeanstalkdJob; use Illuminate\Support\Str; @@ -13,6 +14,13 @@ class QueueBeanstalkdQueueTest extends TestCase { + protected function setUp(): void + { + Connection::$totalTransactions = 0; + + parent::setUp(); + } + protected function tearDown(): void { m::close(); diff --git a/tests/Queue/QueueRedisQueueTest.php b/tests/Queue/QueueRedisQueueTest.php index 2060772d78a8..7dc0ac55b294 100644 --- a/tests/Queue/QueueRedisQueueTest.php +++ b/tests/Queue/QueueRedisQueueTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Queue; use Illuminate\Contracts\Redis\Factory; +use Illuminate\Database\Connection; use Illuminate\Queue\LuaScripts; use Illuminate\Queue\Queue; use Illuminate\Queue\RedisQueue; @@ -13,6 +14,13 @@ class QueueRedisQueueTest extends TestCase { + protected function setUp(): void + { + Connection::$totalTransactions = 0; + + parent::setUp(); + } + protected function tearDown(): void { m::close();