diff --git a/src/Illuminate/Bus/Batch.php b/src/Illuminate/Bus/Batch.php index 717d1c4ab11d..72a2f34c00f9 100644 --- a/src/Illuminate/Bus/Batch.php +++ b/src/Illuminate/Bus/Batch.php @@ -242,11 +242,7 @@ public function recordSuccessfulJob(string $jobId) $counts = $this->decrementPendingJobs($jobId); if ($this->hasProgressCallbacks()) { - $batch = $this->fresh(); - - (new Collection($this->options['progress']))->each(function ($handler) use ($batch) { - $this->invokeHandlerCallback($handler, $batch); - }); + $this->invokeCallbacks('progress'); } if ($counts->pendingJobs === 0) { @@ -254,20 +250,25 @@ public function recordSuccessfulJob(string $jobId) } if ($counts->pendingJobs === 0 && $this->hasThenCallbacks()) { - $batch = $this->fresh(); - - (new Collection($this->options['then']))->each(function ($handler) use ($batch) { - $this->invokeHandlerCallback($handler, $batch); - }); + $this->invokeCallbacks('then'); } if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) { - $batch = $this->fresh(); + $this->invokeCallbacks('finally'); + } + } - (new Collection($this->options['finally']))->each(function ($handler) use ($batch) { - $this->invokeHandlerCallback($handler, $batch); + /** + * Invoke the callbacks of the given type. + */ + public function invokeCallbacks(string $type, ?\Throwable $e = null): void + { + $batch = $this->fresh(); + + (new Collection($this->options[$type])) + ->each(function ($handler) use ($batch, $e) { + $this->invokeHandlerCallback($handler, $batch, $e); }); - } } /** @@ -346,28 +347,22 @@ public function recordFailedJob(string $jobId, $e) $this->cancel(); } - if ($this->hasProgressCallbacks() && $this->allowsFailures()) { - $batch = $this->fresh(); + if ($this->allowsFailures()) { + if ($this->hasProgressCallbacks()) { + $this->invokeCallbacks('progress', $e); + } - (new Collection($this->options['progress']))->each(function ($handler) use ($batch, $e) { - $this->invokeHandlerCallback($handler, $batch, $e); - }); + if ($this->hasFailureCallbacks()) { + $this->invokeCallbacks('failure', $e); + } } if ($counts->failedJobs === 1 && $this->hasCatchCallbacks()) { - $batch = $this->fresh(); - - (new Collection($this->options['catch']))->each(function ($handler) use ($batch, $e) { - $this->invokeHandlerCallback($handler, $batch, $e); - }); + $this->invokeCallbacks('catch', $e); } if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) { - $batch = $this->fresh(); - - (new Collection($this->options['finally']))->each(function ($handler) use ($batch, $e) { - $this->invokeHandlerCallback($handler, $batch, $e); - }); + $this->invokeCallbacks('finally'); } } @@ -402,6 +397,16 @@ public function hasFinallyCallbacks() return isset($this->options['finally']) && ! empty($this->options['finally']); } + /** + * Determine if the batch has "failure" callbacks. + * + * @return bool + */ + public function hasFailureCallbacks() + { + return isset($this->options['failure']) && ! empty($this->options['failure']); + } + /** * Cancel the batch. * diff --git a/src/Illuminate/Bus/PendingBatch.php b/src/Illuminate/Bus/PendingBatch.php index 9538074d7be4..7bd4972ba1f2 100644 --- a/src/Illuminate/Bus/PendingBatch.php +++ b/src/Illuminate/Bus/PendingBatch.php @@ -237,14 +237,23 @@ public function finallyCallbacks() } /** - * Indicate that the batch should not be cancelled when a job within the batch fails. - * - * @param bool $allowFailures - * @return $this + * Indicate that the batch should not be cancelled when a job within the batch fails; + * optionally add callbacks to be executed upon each job failure (this may be useful for + * running other jobs when a job fails). */ - public function allowFailures($allowFailures = true) + public function allowFailures(bool|callable|Closure|array $param = true): self { - $this->options['allowFailures'] = $allowFailures; + if (! is_bool($param)) { + $param = Arr::wrap($param); + + foreach ($param as $callback) { + $this->options['failure'][] = $callback instanceof Closure + ? new SerializableClosure($callback) + : $callback; + } + } + + $this->options['allowFailures'] = (bool) $param; return $this; } @@ -259,6 +268,14 @@ public function allowsFailures() return Arr::get($this->options, 'allowFailures', false) === true; } + /** + * Get the "failure" callbacks that have been registered with the pending batch. + */ + public function failureCallbacks(): array + { + return $this->options['failure'] ?? []; + } + /** * Set the name for the batch. *