kirschbaum-development/laravel-queue-batch-retry
Retry failed jobs in Laravel queue batches with a simple artisan command. This package re-dispatches failed batch jobs while preserving batch context, so you can recover from failures without manually tracking or re-queuing individual jobs.
Turning "batch failure" from a scramble into a runbook step. Batched work is where customer-visible promises live: bulk imports and exports, invoice/report generation, notification and email fan-outs, media pipelines, CRM/ERP syncs, per-tenant provisioning. Today a partial failure means either re-running the whole batch (duplicative, customer-visible, expensive) or hand-picking failed job UUIDs from failed_jobs. This package makes "retry only the failed jobs, minus the ones we know are broken" a repeatable operation — the prerequisite for committing to any recovery expectation at all.
Build vs. buy: buy, with a deliberately cheap exit. The alternative is a homegrown Artisan command over job_batches / failed_jobs — cheap to write once, expensive to own. It drifts from Laravel internals, accretes one-off filters, and lives in one engineer's head. This package covers the same ground for one Composer line and can be swapped for a short internal script if abandoned. That asymmetry makes adoption the default rather than a debate worth scheduling.
Roadmap: surgical recovery is now a real option, so scope can grow. The --exclude-filter flag added in 1.2.2 is the strategically interesting change. The prior choice was binary — replay the entire batch, or name individual jobs. Scoped operations like retry everything in the Billing namespace except the Stripe integration we know is down are now expressible. Any roadmap item currently assuming "batch failure = full re-run" should be re-estimated; removing duplicate side effects from the critical path is a product-quality gain, not just an ops convenience.
Blast-radius control becomes a product lever. Retrying is a write against production queue state. Over-broad selection floods workers and duplicates customer-visible effects; over-broad exclusion silently skips the one job that needed to run. Filtering is the difference between a 5-job retry and a 5,000-job duplicate send — and since that is a command-syntax decision, it belongs in a documented runbook, not in tribal knowledge.
Keeps us on native Laravel batching. This supports the standing decision not to migrate to a durable-execution platform for this class of work. It is operational tooling, not platform: no schema changes, no vendor contract, no new product surface, off the deploy path.
Use cases: bulk CRM/ERP syncs, data imports and exports, large notification fan-outs, bulk invoice/report generation, media processing, per-tenant provisioning. The common shape is a long-running batch of mostly independent jobs where a minority fail transiently.
Consider it when:
Bus::batch() and the native job_batches / failed_jobs tables. Without native batching there is nothing to act on — this is table stakes.--filter) and carve out a known-bad dependency (--exclude-filter). That is the gap between Laravel core's whole-batch queue:retry-batch and what incidents actually demand. If you don't need filters, prefer core and take the smaller risk.^1.2 so the exclusion flag isn't silently missing on a stale ops box still on 1.2.1.Look elsewhere — or stay manual — when:
Answers needed before go/no-go (1–3 are pilot-only constraints, not blockers):
--filter and --exclude-filter match against — job class, queue, connection, batch name — and is it exact, prefix, substring, or regex?tries, maxExceptions, and allowFailures?catch/finally still fire?For executives — one paragraph: This is a small, low-cost operational improvement, not a platform bet. Today, when a background batch partially fails — a bulk import, a notification send, a data sync — recovery means either a full re-run (expensive, duplicative, customer-visible) or a manual, engineer-by-engineer script. A lightweight open-source package closes that gap: operators can retry only the failed portion of a batch, and with the 1.2.2 release, optionally exclude jobs known to be broken — so during an incident we make forward progress on the healthy part of a batch instead of waiting for a fix. Cost is a dependency line plus roughly a day of validation; if the package is ever abandoned, we replace it with a short internal script. Recommendation: adopt as internal tooling, pilot on one non-critical batch workflow, and require documented filter behavior before production use.
For engineering — the ask: Add kirschbaum-development/laravel-queue-batch-retry (^1.2, dev/ops dependency) under standard Laravel auto-discovery. It's a thin wrapper over job_batches and failed_jobs, registers an Artisan command, needs no migrations or config, and preserves batch callbacks (then/catch/finally) so bookkeeping stays correct. --exclude-filter is new in 1.2.2 and purely additive — pin at ^1.2 so it isn't silently absent on an ops box still running 1.2.1.
The work is not the install; it is characterization. Before this touches production we need, written into the retry runbook with worked examples:
catch/finally.Boundaries to state in the same breath: single maintainer, low bus factor, likely to lag future Laravel majors — acceptable for a tool off the deploy path, not for a hard runtime dependency. Name queue:retry-batch (core, whole-batch) and Horizon as the adjacent tools, and decide which one owns retries so we don't end up with three paths to the same write. If the roadmap later calls for dependency graphs, audit trails, or approval gates, this package is not the answer, and we should say so early rather than retrofit it.
How can I help you explore Laravel packages today?