Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Queue Bundle Laravel Package

mmucklo/queue-bundle

Symfony bundle for background job queues with worker commands, job scheduling, and pluggable backends. Offload time-consuming tasks and process them asynchronously using Doctrine, MongoDB, Redis, or other supported queue stores.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the framework check. This is DtcQueueBundle — a Symfony 2.7–5.x bundle. It ships a Bundle class, a DI extension, a compiler pass, a YAML configuration tree, and Symfony Console commands (dtc:queue:run, stalled-job recovery, stats). There is no service provider, no facade, and no Illuminate\Queue\Queue driver, so you cannot composer require it into a Laravel app and call dispatch(). If you are on Laravel, the rest of this section is reference reading; the working equivalent is ShouldQueue + php artisan queue:work, and the rest of the assessment tells you which ideas are worth copying.

Install and register (Symfony):

composer require mmucklo/queue-bundle
// config/bundles.php  (Symfony 4/5)
return [
    // ...
    Dtc\QueueBundle\DtcQueueBundle::class => ['all' => true],
];
// app/AppKernel.php  (Symfony 2/3)
$bundles[] = new Dtc\QueueBundle\DtcQueueBundle();

Pick one backend and configure it. The whole value proposition is that manager.type is swappable — doctrine (MySQL/Postgres/any ORM), mongodb (Doctrine ODM), redis, rabbitmq, beanstalkd, or a custom class — with a per-backend block underneath:

# config/packages/dtc_queue.yaml
dtc_queue:
    manager:
        type: doctrine
        doctrine:
            # connection / entity manager options

Copy the exact block for your backend from the README's Configuration section. The per-backend keys differ and are not guessable.

Where to look first, in order:

  1. The README Configuration block for your chosen transport — this is the only accurate source for config keys.
  2. JobManagerInterface — the single abstraction everything else hangs off. Read this before reading any adapter.
  3. The bundled worker command (dtc:queue:run) — its options define the runtime contract (max jobs, max time, sleep, worker name).
  4. The job-status entity/document — the pending → running → success/failure lifecycle is what the stalled-job recovery command depends on.

First use case: a delayed transactional email or a report/PDF export. Something idempotent, non-critical, and slow enough to be worth backgrounding. Write a plain PHP job class with the mailer or the report service injected, push it from a controller, run the worker in the foreground until it works, then move it under Supervisor.

Laravel translation of the same first use case: php artisan make:job SendWelcomeEmail, implement ShouldQueue, dispatch it, php artisan queue:work --max-time=3600 under Supervisor. Same shape, zero new dependencies.

Implementation Patterns

Depend on the interface, not the manager. Application code should type-hint JobManagerInterface (or inject it via the container) and call push/schedule. That single discipline is what makes the Redis→RabbitMQ migration a config change instead of a rewrite. If you find yourself referencing DoctrineJobManager or RedisJobManager from a controller, the abstraction has already failed.

Job classes are plain services. The convention is a normal PHP class with constructor-injected dependencies and a run()-style entry point. Because Symfony's container autowires them, the job class is testable in isolation and the worker is just a loop that resolves the class and calls the method. The Laravel analogue is a ShouldQueue job whose handle() gets DI'd dependencies — same idea, first-party.

Per-environment transport swapping. The pattern worth stealing: synchronous/immediate execution in dev and test (so failures surface in the request), Redis or RabbitMQ in production. In Symfony this is a manager.type change per environment. In Laravel it's QUEUE_CONNECTION=sync locally and redis in production — no bundle required.

Bounded retries and delays configured on the job, not globally. The bundle supports delayed jobs, max retries, and expiry. Set them per job class rather than relying on a global default, because a webhook retry and a PDF export want very different retry budgets. Anything with an external side effect must be idempotent: at-least-once is the only delivery guarantee you get from any of these transports.

Run the worker under a process supervisor, one process per queue. Supervisor or systemd, with restart-on-exit and a log file you actually tail. Long-running workers hold code in memory — every deploy needs a worker restart, or you'll run old code indefinitely and debug it for an afternoon.

Schedule the stalled-job recovery command. This is the bundle's best operational idea and the one thing to carry into Laravel. A worker killed mid-job leaves rows stuck in running forever; recovery reclaims them. In Laravel the analogues are retry_after (Redis/database visibility timeout) and scheduled queue:retry/queue:flush hygiene.

Custom transport as the extension point. If the existing adapters don't fit, implement the manager interface and register it as a service — that's the designed seam. Realistically: don't. A custom transport is a maintenance commitment with no upstream support.

Transport migration pattern. Because the abstraction is at the manager level, a broker swap is: stand up the new backend, run workers for both transports concurrently during cutover, flip producers over, drain the old queue, decommission. Producers and consumers can be on different transports for the duration, which is what makes this safe.

Gotchas and Tips

The support ceiling is the blocker, not the design. Symfony 2/3/4 are EOL and the matrix stops at Symfony 5, which implies PHP 7.x/8.0-era code with no Symfony 6/7 or PHP 8.2+ assurance. On a modern Laravel 10/11 stack that's an immediate no. Verify the actual composer.json constraints on the default branch before spending any time on a spike.

Zero dependents is the strongest signal in the record. 120 stars and no downstream production users means no community-forced bug fixes and no compatibility patches. Single maintainer, no evident release cadence, no security policy. Budget for a fork-and-own, not for support.

The Doctrine ORM transport is the weak link. A SQL table as a queue invites row-lock contention under concurrency, table bloat, and polling latency. If you use it: index the status/priority/created-at columns, add a retention/pruning job, and measure throughput under realistic worker counts before trusting it. Mongo/ODM avoids lock contention but adds an operational dependency you may not otherwise run.

Orphaned jobs fail silently. Worker crash → rows stuck in running → jobs that never complete and never error. Nothing alerts you. The recovery command must be on a schedule, and you should alert on oldest-pending age and queue depth, not just on worker exit codes.

Poison messages need a terminal state. A job that always throws must hit a bounded retry count and land in a failed/dead state — not loop. Check the default max_retries for whatever transport you pick; the defaults differ per adapter.

Serialized payloads outlive deployments. Jobs queued before a deploy will be deserialized by workers running new code. Renaming a job class or changing a constructor signature while jobs are in flight produces failures that look like infrastructure problems. Deploy workers before or after, never mid-drain, and keep job payloads to scalars and IDs — re-fetch entities inside the job.

Config keys are not guessable. The per-backend YAML blocks differ substantially and the Symfony config tree validates at container-compile time, so a wrong key fails the whole cache warm. Copy from the README rather than inventing. A manager.type that doesn't match the populated block is a classic silent-misconfiguration source.

The bundled dashboard is an admin surface. If you enable it, gate the routes explicitly — an unauthenticated queue dashboard leaks job payloads (which frequently contain user data, email addresses, and tokens). In Laravel, Horizon's Horizon::auth() serves the same purpose.

Debugging checklist, in order: is the worker process actually running (ps/Supervisor status); is the job row transitioning pending → running → success (query the table directly); is the worker log showing a caught exception; is the retry count exhausted; is the job stuck in running (means the worker died, not the job failed). Ninety percent of "the queue is broken" resolves at step one or two.

The real takeaway for a Laravel developer. Don't bridge this bundle into Laravel — you'd be running two containers, two config systems, and two consoles to get a capability queue:work already provides, and you'd own the fork. Instead harvest the two ideas it gets right: a persisted job-status lifecycle you can query and alert on, and a scheduled stalled-job recovery pass. Both are a few hundred lines on top of Laravel's native queue, with no third-party risk and no divergence from the framework.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource