Skip to content

Commit 9c2e8a9

Browse files
author
Yitz Willroth
committed
feat: add job failure callbacks to batches
1 parent d3e8791 commit 9c2e8a9

File tree

2 files changed

+76
-53
lines changed

2 files changed

+76
-53
lines changed

src/Illuminate/Bus/Batch.php

Lines changed: 53 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -101,18 +101,19 @@ class Batch implements Arrayable, JsonSerializable
101101
/**
102102
* Create a new batch instance.
103103
*
104-
* @param \Illuminate\Contracts\Queue\Factory $queue
105-
* @param \Illuminate\Bus\BatchRepository $repository
106-
* @param string $id
107-
* @param string $name
108-
* @param int $totalJobs
109-
* @param int $pendingJobs
110-
* @param int $failedJobs
111-
* @param array $failedJobIds
112-
* @param array $options
113-
* @param \Carbon\CarbonImmutable $createdAt
114-
* @param \Carbon\CarbonImmutable|null $cancelledAt
115-
* @param \Carbon\CarbonImmutable|null $finishedAt
104+
*
105+
* @param \Illuminate\Contracts\Queue\Factory $queue
106+
* @param \Illuminate\Bus\BatchRepository $repository
107+
* @param string $id
108+
* @param string $name
109+
* @param int $totalJobs
110+
* @param int $pendingJobs
111+
* @param int $failedJobs
112+
* @param array $failedJobIds
113+
* @param array $options
114+
* @param \Carbon\CarbonImmutable $createdAt
115+
* @param \Carbon\CarbonImmutable|null $cancelledAt
116+
* @param \Carbon\CarbonImmutable|null $finishedAt
116117
*/
117118
public function __construct(
118119
QueueFactory $queue,
@@ -225,8 +226,8 @@ public function processedJobs()
225226
* Get the percentage of jobs that have been processed (between 0-100).
226227
*
227228
* @return int
228-
*/
229-
public function progress()
229+
**/
230+
public function progress(): int
230231
{
231232
return $this->totalJobs > 0 ? round(($this->processedJobs() / $this->totalJobs) * 100) : 0;
232233
}
@@ -236,38 +237,39 @@ public function progress()
236237
*
237238
* @param string $jobId
238239
* @return void
239-
*/
240+
**/
240241
public function recordSuccessfulJob(string $jobId)
241242
{
242243
$counts = $this->decrementPendingJobs($jobId);
243244

244245
if ($this->hasProgressCallbacks()) {
245-
$batch = $this->fresh();
246-
247-
(new Collection($this->options['progress']))->each(function ($handler) use ($batch) {
248-
$this->invokeHandlerCallback($handler, $batch);
249-
});
246+
$this->invokeCallbacks('progress');
250247
}
251248

252249
if ($counts->pendingJobs === 0) {
253250
$this->repository->markAsFinished($this->id);
254251
}
255252

256253
if ($counts->pendingJobs === 0 && $this->hasThenCallbacks()) {
257-
$batch = $this->fresh();
258-
259-
(new Collection($this->options['then']))->each(function ($handler) use ($batch) {
260-
$this->invokeHandlerCallback($handler, $batch);
261-
});
254+
$this->invokeCallbacks('then');
262255
}
263256

264257
if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) {
265-
$batch = $this->fresh();
258+
$this->invokeCallbacks('finally');
259+
}
260+
}
261+
262+
/**
263+
* Invoke the callbacks of the given type.
264+
*/
265+
public function invokeCallbacks(string $type, ?\Throwable $e = null): void
266+
{
267+
$batch = $this->fresh();
266268

267-
(new Collection($this->options['finally']))->each(function ($handler) use ($batch) {
268-
$this->invokeHandlerCallback($handler, $batch);
269+
(new Collection($this->options[$type]))
270+
->each(function ($handler) use ($batch, $e) {
271+
$this->invokeHandlerCallback($handler, $batch, $e);
269272
});
270-
}
271273
}
272274

273275
/**
@@ -338,36 +340,30 @@ public function hasFailures()
338340
* @param \Throwable $e
339341
* @return void
340342
*/
341-
public function recordFailedJob(string $jobId, $e)
343+
public function recordFailedJob($jobId, $e)
342344
{
343345
$counts = $this->incrementFailedJobs($jobId);
344346

345347
if ($counts->failedJobs === 1 && ! $this->allowsFailures()) {
346348
$this->cancel();
347349
}
348350

349-
if ($this->hasProgressCallbacks() && $this->allowsFailures()) {
350-
$batch = $this->fresh();
351+
if ($this->allowsFailures()) {
352+
if ($this->hasProgressCallbacks()) {
353+
$this->invokeCallbacks('progress', $e);
354+
}
351355

352-
(new Collection($this->options['progress']))->each(function ($handler) use ($batch, $e) {
353-
$this->invokeHandlerCallback($handler, $batch, $e);
354-
});
356+
if ($this->hasFailureCallbacks()) {
357+
$this->invokeCallbacks('failure', $e);
358+
}
355359
}
356360

357361
if ($counts->failedJobs === 1 && $this->hasCatchCallbacks()) {
358-
$batch = $this->fresh();
359-
360-
(new Collection($this->options['catch']))->each(function ($handler) use ($batch, $e) {
361-
$this->invokeHandlerCallback($handler, $batch, $e);
362-
});
362+
$this->invokeCallbacks('catch', $e);
363363
}
364364

365365
if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) {
366-
$batch = $this->fresh();
367-
368-
(new Collection($this->options['finally']))->each(function ($handler) use ($batch, $e) {
369-
$this->invokeHandlerCallback($handler, $batch, $e);
370-
});
366+
$this->invokeCallbacks('finally');
371367
}
372368
}
373369

@@ -402,6 +398,16 @@ public function hasFinallyCallbacks()
402398
return isset($this->options['finally']) && ! empty($this->options['finally']);
403399
}
404400

401+
/**
402+
* Determine if the batch has "failure" callbacks.
403+
*
404+
* @return bool
405+
*/
406+
public function hasFailureCallbacks()
407+
{
408+
return isset($this->options['failure']) && ! empty($this->options['failure']);
409+
}
410+
405411
/**
406412
* Cancel the batch.
407413
*
@@ -446,8 +452,8 @@ public function delete()
446452
* Invoke a batch callback handler.
447453
*
448454
* @param callable $handler
449-
* @param \Illuminate\Bus\Batch $batch
450-
* @param \Throwable|null $e
455+
* @param \Illuminate\Bus\Batch $batch
456+
* @param \Throwable|null $e
451457
* @return void
452458
*/
453459
protected function invokeHandlerCallback($handler, Batch $batch, ?Throwable $e = null)

src/Illuminate/Bus/PendingBatch.php

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,14 +237,23 @@ public function finallyCallbacks()
237237
}
238238

239239
/**
240-
* Indicate that the batch should not be cancelled when a job within the batch fails.
241-
*
242-
* @param bool $allowFailures
243-
* @return $this
240+
* Indicate that the batch should not be cancelled when a job within the batch fails;
241+
* optionally add callbacks to be executed upon each job failure (this may be useful for
242+
* running other jobs when a job fails).
244243
*/
245-
public function allowFailures($allowFailures = true)
244+
public function allowFailures(bool|callable|Closure|array $param = true): self
246245
{
247-
$this->options['allowFailures'] = $allowFailures;
246+
if (! is_bool($param)) {
247+
$param = Arr::wrap($param);
248+
249+
foreach ($param as $callback) {
250+
$this->options['failure'][] = $callback instanceof Closure
251+
? new SerializableClosure($callback)
252+
: $callback;
253+
}
254+
}
255+
256+
$this->options['allowFailures'] = (bool) $param;
248257

249258
return $this;
250259
}
@@ -259,6 +268,14 @@ public function allowsFailures()
259268
return Arr::get($this->options, 'allowFailures', false) === true;
260269
}
261270

271+
/**
272+
* Get the "failure" callbacks that have been registered with the pending batch.
273+
*/
274+
public function failureCallbacks(): array
275+
{
276+
return $this->options['failure'] ?? [];
277+
}
278+
262279
/**
263280
* Set the name for the batch.
264281
*

0 commit comments

Comments
 (0)