jms/job-queue-bundle
A Symfony bundle that adds a persistent, Doctrine-backed job queue to your application. It supports job scheduling, dependencies, retries, parallel workers, and a web interface for monitoring and managing queued jobs.
Architecture fit — the load-bearing finding: this is not a Laravel package. jms/job-queue-bundle is a Symfony Bundle. It registers itself through Symfony\Component\HttpKernel\Bundle\Bundle, boots via Symfony's DI container compiler passes, and exposes its functionality as jms-job-queue:* Symfony Console commands. Laravel has no bundle/DI-compiler-pass concept; there is no service provider, no facade, no config publishing, no Artisan integration. Dropping this into a Laravel application is not an integration task, it is a reimplementation task. For a Laravel-centric stack the correct TPM framing is not "how do we adopt this" but "what does this package's design tell us about requirements we may be under-serving natively."
What it actually does, and whether we need it. The bundle persists Symfony Console invocations as Doctrine ORM entities (Job), lets you enqueue and schedule them, and provides a long-running jms-job-queue:run worker that executes and tracks them with dependency ordering between jobs. That is a genuinely useful shape: durable, inspectable, schedulable command execution with a dependency graph (job B waits on job A). Laravel's nearest equivalents are Queue::push(new SomeJob) for background work, $schedule->command() for cron-style scheduling, and Bus::chain() / Bus::batch() for sequencing — all native, all supported, and Bus::batch() covers the dependency-ordering use case that is this bundle's differentiator.
Technical risk. High and largely disqualifying for new work:
--ignore-platform-reqs or a forked constraint set, both of which are unpatchable technical debt.jms/di-extra-bundle-era Symfony patterns. Doctrine is explicitly not the Laravel default; Laravel's Eloquent and Doctrine's Unit of Work do not compose cleanly in one process.Key questions for the requester:
Bus::batch() and Horizon tags cover both.composer why-not jms/job-queue-bundle against the real composer.json before any further analysis.Stack fit: negative for Laravel. There is no supported path. A Laravel integration would require (a) a Laravel service provider to boot Symfony's container semantics, (b) an Eloquent-or-Doctrine hybrid persistence layer for the Job entity, (c) a Supervisor-managed jms-job-queue:run process outside Laravel's queue:work lifecycle, and (d) bridging two logging, event, and container systems. That is a multi-week engineering bet on an abandoned dependency to duplicate functionality Laravel ships in core. Recommend rejecting on fit.
Recommended replacement, mapping capability to native Laravel:
| Bundle capability | Laravel-native substitute |
|---|---|
| Enqueue a console command as a job | Artisan::queue('cmd') or a ShouldQueue job wrapping Artisan::call |
| Persistent job records | jobs / failed_jobs tables, queue:monitor |
| Cron-style scheduling | routes/console.php / Kernel::schedule() with withoutOverlapping(), onOneServer() |
| Job dependency ordering | Bus::chain() (serial) or Bus::batch() with ->allowFailures() (fan-out + continuation) |
| Worker execution and retries | queue:work with --tries, --backoff, Horizon for Redis |
| Observability | Horizon dashboard, failed_jobs UI, Telescope |
Migration path if something is already running on this bundle. Determine first whether it is embedded in a Symfony service or was force-fitted into Laravel. For a Symfony service: freeze the version, pin transitive deps, and plan a move to symfony/messenger (the first-party successor covering exactly this ground — transport, retries, failure transport, worker). For a Laravel service: the migration is a job-by-job re-expression into Laravel queues, table-by-table data port of Job rows for in-flight work only, and a cutover behind a feature flag with both workers running during the drain window.
Compatibility and sequencing. Sequence as: (1) inventory every enqueue site and scheduled command, (2) express each as a Laravel job class with identical payload contract, (3) stand up the native queue and dual-write, (4) drain the Job table to zero with the old worker still running, (5) decommission the old worker, (6) drop the schema. Do not attempt a partial coexistence where the same logical job can be picked up by both workers — duplicate execution is the dominant migration failure mode here.
If a Symfony service genuinely requires this class of functionality, do not adopt the bundle; adopt symfony/messenger. Same conceptual model, first-party maintenance, PHP 8 and Symfony 6/7 support, and a documented upgrade path. The only reason to choose jms/job-queue-bundle in 2025 is a hard constraint on an existing install, and even then the correct disposition is "contain and schedule removal," not "extend."
Maintenance burden is the deciding operational factor. An unmaintained package that owns a database schema, a long-running worker process, and a scheduling loop is not a passive dependency — it is infrastructure we inherit without a vendor. Every PHP minor upgrade becomes a fork-and-patch exercise. Budget a standing maintenance line item, or better, budget the migration instead.
Support. No upstream. 334 stars is a small community for a package of this blast radius; the repository's issues are not a support channel. On-call engineers will be debugging a 2019 codebase against a modern runtime with no upstream reference. Knowledge concentration risk is severe: whoever originally wired this up becomes a single point of failure.
Scaling characteristics. The design is DB-polling based: workers poll the Job table for claimable work. That produces row contention and index pressure at high enqueue rates, and the Job table grows unbounded without a retention policy — an operational chore the bundle does not handle for you. Horizontal scale is possible (multiple jms-job-queue:run processes) but correctness depends on the claim/lock semantics in an unaudited codebase. Contrast with Redis-backed Laravel queues, which are purpose-built for throughput and have Horizon for autoscaling and per-queue worker pools.
Failure modes to plan for:
Ramp-up. Deceptively steep. The API surface looks small, but effective use requires Symfony container and compiler-pass fluency, Doctrine entity mapping and schema-migration ownership, and Supervisord or systemd unit management for the worker — a set of skills largely absent from a Laravel team and unlikely to be reused elsewhere in the estate. A Laravel engineer is productive on Bus::batch() in an afternoon; productive-and-confident on this bundle in a sprint, with residual risk they never fully retire.
Recommendation. Reject for Laravel. The 27.52 score and 2019 release date are consistent with the technical picture rather than incidental to it. Redirect the requirement to Laravel's native queue, scheduler, and Bus::batch(), with Horizon for operational visibility; if a Symfony service is in scope, standardize on symfony/messenger. Treat this package as an inventory item to retire, not a candidate to adopt.
How can I help you explore Laravel packages today?