diff --git a/src/Illuminate/Bus/Queueable.php b/src/Illuminate/Bus/Queueable.php index 3d3bbb9b290e..1c8951eca8ab 100644 --- a/src/Illuminate/Bus/Queueable.php +++ b/src/Illuminate/Bus/Queueable.php @@ -199,6 +199,11 @@ public function chain($chain) */ public function prependToChain($job) { + $job = match (true) { + $job instanceof PendingBatch => new ChainedBatch($job), + default => $job, + }; + $this->chained = Arr::prepend($this->chained, $this->serializeJob($job)); return $this; @@ -212,6 +217,11 @@ public function prependToChain($job) */ public function appendToChain($job) { + $job = match (true) { + $job instanceof PendingBatch => new ChainedBatch($job), + default => $job, + }; + $this->chained = array_merge($this->chained, [$this->serializeJob($job)]); return $this; diff --git a/tests/Integration/Queue/JobChainingTest.php b/tests/Integration/Queue/JobChainingTest.php index a742e7ec142d..32a8f6957b99 100644 --- a/tests/Integration/Queue/JobChainingTest.php +++ b/tests/Integration/Queue/JobChainingTest.php @@ -288,6 +288,30 @@ public function testChainJobsCanBeAppended() $this->assertTrue(JobChainAddingAddedJob::$ranAt->isAfter(JobChainAddingExistingJob::$ranAt)); } + public function testChainJobsCanBePrependedBatch() + { + Bus::chain([ + new JobChainAddingPrependedBatch('j1'), + new JobChainingNamedTestJob('j2'), + ])->dispatch(); + + $this->runQueueWorkerCommand(['--stop-when-empty' => true]); + + $this->assertEquals(['j1', 'b1', 'b2', 'j2'], JobRunRecorder::$results); + } + + public function testChainJobsCanBeAppendedBatch() + { + Bus::chain([ + new JobChainAddingAppendingBatch('j1'), + new JobChainingNamedTestJob('j2'), + ])->dispatch(); + + $this->runQueueWorkerCommand(['--stop-when-empty' => true]); + + $this->assertEquals(['j1', 'j2', 'b1', 'b2'], JobRunRecorder::$results); + } + public function testChainJobsCanBeAppendedWithoutExistingChain() { JobChainAddingAppendingJob::dispatch(); @@ -652,6 +676,50 @@ public function handle() } } +class JobChainAddingAppendingBatch implements ShouldQueue +{ + use Dispatchable, InteractsWithQueue, Queueable; + + public string $id; + + public function __construct(string $id) + { + $this->id = $id; + } + + public function handle() + { + $this->appendToChain(Bus::batch([ + new JobChainingNamedTestJob('b1'), + new JobChainingNamedTestJob('b2'), + ])); + + JobRunRecorder::record($this->id); + } +} + +class JobChainAddingPrependedBatch implements ShouldQueue +{ + use Dispatchable, InteractsWithQueue, Queueable; + + public string $id; + + public function __construct(string $id) + { + $this->id = $id; + } + + public function handle() + { + $this->prependToChain(Bus::batch([ + new JobChainingNamedTestJob('b1'), + new JobChainingNamedTestJob('b2'), + ])); + + JobRunRecorder::record($this->id); + } +} + class JobChainAddingExistingJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable;