All skills
asyrafhussin avatar

/laravel-queues

@2631530

Laravel 13 queue and job patterns — driver choice, job design (idempotency, ShouldQueue, model serialisation), retry and failure handling, worker scaling, Bus batching and chaining, Horizon when warranted, queue testing. Use when designing async jobs, scheduling background work, configuring Horizon, debugging stuck jobs, or auditing queue health. Triggers on "Laravel queue", "Laravel job", "background job", "Horizon setup", "failed jobs", "Bus batch", "queue worker tuning".

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/laravel-queues

This session only. Nothing lands on disk.

rulesbus-batch-failure-handling.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Batch Failure Handling — allowFailures() and Callbacks

Impact: HIGH (Default batch behaviour cancels remaining jobs on first failure; allowFailures() keeps them running)

Bus::batch has an opinion about failures: by default, a single job failure cancels the rest of the batch. Any unstarted jobs in the batch are silently dropped; in-flight jobs complete but don't trigger further dispatches.

For a "process these 1000 CSV rows" batch where one row failing shouldn't stop the other 999, that default is wrong. Use allowFailures().

For a "create these 3 resources" batch where if any fails, the others are pointless, the default IS right.

Default: fail-fast

// ✅ Fail-fast: if one job fails, cancel the rest

Bus::batch([
    new CreateOrderRecord($data),
    new ReserveInventory($data),
    new ChargePayment($data),
])->catch(function (Batch $batch, Throwable $e) {
    // Triggered on the FIRST failure; remaining jobs cancelled
    OrderFlow::rollback($data);
})->dispatch();

Right call here: you don't want ChargePayment to run if ReserveInventory failed.

allowFailures(): keep going

// ✅ Resilient batch: one row failing doesn't stop the import

$batch = Bus::batch(
    $rows->map(fn ($row) => new ImportCsvRow($row))
)->name('CSV import')
 ->allowFailures()                            // ← critical
 ->then(function (Batch $batch) {
    // All processed (some may have failed)
    $report = "Imported {$batch->processedJobs()} / {$batch->totalJobs}; failed: {$batch->failedJobs}";
    Mail::to($user)->send(new CsvImportReport($report));
 })
 ->dispatch();

allowFailures() semantics:

  • Failed jobs go to failed_jobs (same as a normal job failure)
  • The batch's then callback fires when all jobs have either succeeded OR failed
  • The batch's catch callback NEVER fires (since failures are allowed)
  • $batch->failedJobs and $batch->processedJobs() show the split

Querying batch state

For UI / monitoring:

$batch = Bus::findBatch($batchId);

$batch->pendingJobs;         // not yet processed
$batch->totalJobs;           // total count
$batch->processedJobs();     // pendingJobs done (success + fail)
$batch->failedJobs;          // count of failures
$batch->progress();          // 0-100 percentage
$batch->finished();          // bool: all jobs processed
$batch->cancelled();         // bool: cancel() was called

Use this to render a progress page:

// routes/web.php
Route::get('/batches/{id}/progress', function (string $id) {
    $batch = Bus::findBatch($id);
    abort_unless($batch, 404);
    return [
        'total' => $batch->totalJobs,
        'done' => $batch->processedJobs(),
        'failed' => $batch->failedJobs,
        'progress' => $batch->progress(),
        'finished' => $batch->finished(),
    ];
});

Cancelling a batch

// Cancel any remaining queued jobs (in-flight jobs still complete)
Bus::findBatch($batchId)->cancel();

// In a job, check before starting work
public function handle(): void
{
    if ($this->batch()->cancelled()) {
        return;
    }
    // do the work
}

Useful pattern: a user clicks "cancel import" on the progress page, you call cancel(), jobs see the cancelled state and exit early.

Incorrect — common mistakes

// ❌ Using catch but not realising it doesn't fire if allowFailures()
Bus::batch($jobs)
    ->allowFailures()
    ->catch(function (Batch $batch, Throwable $e) {
        // NEVER FIRES because allowFailures() is set
        // (failed jobs go to failed_jobs, but the batch carries on)
    })
    ->dispatch();
// ❌ Forgetting allowFailures on a "best effort" batch
Bus::batch($csvJobs)->dispatch();   // first failure → remaining cancelled
// Customer reported one row failed, 5000 others never imported.
// ❌ Trying to "retry the batch" by re-dispatching all jobs
// Bus::batch doesn't have built-in retry. If you want retry semantics,
// either:
//   - Set $tries on the individual jobs (each retries independently)
//   - Filter for failed jobs after the batch and dispatch a NEW batch with just those

When the batch's then should run

then callback fires when:

  • All jobs succeeded (no failures); OR
  • allowFailures() is set AND all jobs have completed (some passed, some failed)

catch fires when:

  • A job fails AND allowFailures() is NOT set (then cancels remaining)

finally always fires after then or catch.

Detection

# Batches without explicit failure mode choice — manual review
grep -rEnA10 'Bus::batch\(' --include='*.php' app/ | grep -B2 -A5 '->dispatch()'

# Look for batches that DON'T have a callback (then/catch/finally) — fire-and-forget batches
# are usually fine, but worth checking they're intentional

Reference: Laravel 13 — Queues: Allowing Failures · Laravel 13 — Queues: Inspecting Batches

Source: SKILL.md on GitHub

No alerts16d3 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The analyzed skill contains high-quality reference guidelines and checklists for configuring and auditing Laravel 13 queue structures and background jobs. No security risks, malicious patterns, or vulnerabilities were identified.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

Signed by skilld at 2631530. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 5 months ago
metadata
{
  "author": "agent-skills",
  "version": "1.0.0"
}

README badge

README badge for asyrafhussin/agent-skills/laravel-queues