stancl/jobpipeline
JobPipeline converts any series of Laravel jobs into event listeners. Chain jobs, send event data to them, and queue the pipeline or push it to a specific queue with minimal configuration.
Architecture fit
Event dispatcher and queue Bus, exposing a single JobPipeline class whose toListener() output is an invokable object registrable anywhere a listener is accepted ($listen array, Event::listen(), or a closure). There is no service provider, no config file, no migrations, and no new runtime abstraction to learn.Bus::chain() plus declarative event→payload mapping.send(closure) mapping: the event object is transformed once into a job payload, so jobs stay event-agnostic and reusable. That decoupling is what a TPM should be buying here — not the sequencing itself.Integration feasibility
composer require stancl/jobpipeline, define job classes, register the pipeline. A Laravel developer can ship a first pipeline in a single PR with no infrastructure change.Technical risk
false when they detect prior completion (e.g. CreateDatabase finding the DB already exists). That is a manual idempotency contract, not an enforced one.return false is a silent, success-shaped cancel. A short-circuited pipeline produces a green job in Horizon with no indication that subsequent steps were skipped. Without explicit logging inside the cancelling job, operators cannot distinguish "finished" from "aborted."SerializableClosure; whether the package does this needs verification before closures are used in queued pipelines.Key questions for the maintainer / spike
$tries, $backoff, $timeout, $queue, and $connection properties honored, or overridden by the pipeline?catch, finally, or per-step failure hook, or only exception propagation and false-cancel?JobPipeline::$shouldBeQueuedByDefault safe to mutate per-test, and does it leak across Octane workers?stancl/tenancy almost certainly depends on it despite GitHub reporting 0 dependents) — this is the real community-size signal.Stack fit
Version and compatibility decision
^1.9 for production. It is the longest-lived GA track, has received every Laravel compatibility release, and carries the PHP 8.4 fixes. Treat 2.x as pre-GA: adopt only if you specifically need the configurable queue-job defaults introduced in 2.0.0-rc1, and only behind a feature-flagged internal wrapper.JobPipeline::make() so a future 1.x→2.x or package-abandonment migration touches one file.Migration path (incremental, reversible)
false when it detects prior completion.EventServiceProvider::$listen. Keep the legacy listener class in place but unwired for one release cycle.shouldBeQueued(true, 'dedicated-queue') only after green.Build-vs-buy note
Bus::chain([...])->dispatch() is equivalent and dependency-free, and offers catch callbacks and chainConnection/chainQueue.Sequencing
Ship the package, adapter, and first pipeline in one sprint. Instrument in sprint two (structured logs per job, Horizon tags, alert on cancel-path logging). Only then widen scope. Budget a half-day spike against the six key questions above before the first queued pipeline touches production data.
Maintenance
Bus::chain() means abandonment is a contained, one-file migration rather than a rewrite.Support
false-return trap during an incident.Scaling
provisioning, exports) so a slow tenant-creation pipeline cannot starve transactional mail.retry_after vs timeout on Redis. A multi-step pipeline is one long-running job; a pipeline exceeding retry_after will be picked up by a second worker and run concurrently with itself. Cap pipeline wall-clock time and set retry_after above the worst-case total.Failure modes
return false) misread as success.SerializesModels, closures) surfacing as an opaque queue error.Ramp-up
false means, and why jobs must be idempotent. Encode those three rules in the runbook and in a code-review checklist, or the first production incident will teach them expensively.How can I help you explore Laravel packages today?