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

Laravel Queue Consumer Laravel Package

jeffersongoncalves/laravel-queue-consumer

A Laravel package for consuming queued jobs, providing a straightforward queue consumer that processes background tasks and integrates with Laravel's existing queue system. It helps keep application workloads moving smoothly with less custom queue plumbing.

View on GitHub
Deep Wiki
Context7

Getting Started

This package turns an external "hub" into the source of truth for queued work: queue-consumer:run pulls a payload, executes it, and reports delivery back via its exit code — 0 means "delivered, drop it", anything else means "not delivered". That contract drives almost everything below.

Minimal steps:

  1. composer require jeffersongoncalves/laravel-queue-consumer (pin ^1.2 — see the Gotchas section, 1.1.x silently loses released jobs).
  2. Publish the config (php artisan vendor:publish) and set the hub endpoint + credentials in .env. Confirm the keys by reading config/queue-consumer.php rather than guessing — this is the first file to open.
  3. Run one job in the foreground: php artisan queue-consumer:run -v. Watch for the process to exit 0 on success. If you see exit 0 and no output, that is the normal path, not a hang.
  4. Only then move it under Supervisor/systemd.

First real use case: a job that can legitimately defer itself — $this->release(60), or middleware like WithoutOverlapping / RateLimited / ThrottlesExceptions. Before 1.2.0 these were traps; on 1.2.0 they are the primary thing to smoke-test, because that is exactly what the release fixed.

Implementation Patterns

One worker process per queue. The new --queue= flag is the headline operational change. A job released by WithoutOverlapping is re-posted to the hub on the queue named by --queue=, which defaults to default. If your hub dispatches to emails, webhooks, and reports, run three supervised consumers:

php artisan queue-consumer:run --queue=emails
php artisan queue-consumer:run --queue=webhooks
php artisan queue-consumer:run --queue=reports

Without this, everything released funnels back onto default and you get a thundering herd on a queue your workers may not even be watching.

Treat release as a first-class control flow. A released job is now round-tripped — re-posted with its original payload and the delay captured by HubJob. So:

public function handle(): void
{
    if (! $this->lock->acquire()) {
        $this->release(30);   // re-enters the hub, comes back in 30s
        return;
    }
    // ...
}

The returned void and bare return matter: don't return $this->release(30) in a void handler, and don't let an exception escape unless you want a non-zero exit.

Make handlers idempotent. A released job is a job the hub will hand out again, and a HubJob re-post is a network call that can itself fail or duplicate. Assume every handle() can run twice with the same payload — guard with WithoutOverlapping, a cache key, or a DB uniqueness check.

Share cache state across consumers. WithoutOverlapping, RateLimited, and ThrottlesExceptions all keep their state in the cache store. With N consumer processes on N hosts, a file or array store gives each process its own private lock and the middleware becomes decorative. Use Redis or the database store, and define named limiters in a service provider exactly as you would for standard queue workers.

Fail loudly by design. The 1.2.0 behaviour is: if the hub refuses the re-post, the command exits non-zero. Do not paper over that — no || true, no 2>/dev/null, no "restart on any exit" loops that hide it. Configure Supervisor with startsecs/stopwaitsecs and alert on FATAL/backoff, otherwise you have reintroduced the 1.1.0 silent-drop with extra steps.

Keep one logical job per payload. Since the hub owns retry state, pushing fan-out into a single consumer job means a partial failure leaves you unable to express which sub-task to retry. Dispatch follow-up work to a separate queue instead.

Gotchas and Tips

  • Audit your 1.1.x history. The pre-1.2.0 failure mode was the worst kind: a released job ran, released itself, exited 0, and the hub marked it delivered. No exception, no failed job, no log line on either side. If you ran 1.1.x in production, grep your logs for jobs that were dispatched but never completed — they are gone, and the fix does not recover them.
  • Upgrade is behaviour-changing, not just bug-fixing. Released jobs used to vanish; now they come back. A job that "worked" because it silently never retried may now retry forever, or loop on a lock it never acquires. Watch retry volume immediately after deploying 1.2.0.
  • --queue= defaults to default — check your hub. A hub that does not send a queue name is stated to keep working, but a hub that sends one and a consumer that ignores it (because you didn't pass --queue) will disagree. Verify by inspecting what your hub actually posts.
  • SyncJob::release() still only flips a flag. The fix lives in HubJob, which captures the delay that the base release($delay) throws away. If you subclass or mock SyncJob in tests, your test double will not exercise the real re-post path — write at least one integration test against the actual consumer command.
  • Delay fidelity is worth checking. The whole point is that the discarded $delay argument is now preserved end-to-end. Verify sub-minute and multi-hour delays survive the round trip; timezone or seconds-vs-milliseconds drift here is subtle and only shows up as "retries feel wrong".
  • WithoutOverlapping + release can livelock. If the lock TTL is shorter than the release delay and the holder never finishes, the job can cycle indefinitely. Set expireAfter deliberately and cap attempts at the hub, since the consumer's own $tries is not the authority anymore.
  • Debugging a vanished job is now tractable. A missing job should mean one of exactly three things: the hub re-post was refused (non-zero exit — check Supervisor logs), the payload was malformed (exception with a stack trace), or the hub dropped it (check hub-side logs). On 1.1.x there was no third signal at all; use the exit code as your first triage step.
  • Exit codes are your metric. Scrape non-zero exits from Supervisor/systemd into your monitoring. That single number is the difference between 1.1.0 and 1.2.0 in observability terms.
  • Extension point: HubJob is the seam for adding tracing IDs, attempt counts, or headers to the re-posted payload. Bind a subclass in the container rather than patching vendor code — the hub needs no changes because the payload is posted back untouched, so any metadata you add must travel outside the job payload itself.
  • Don't run concurrent consumers on the same --queue unless handlers are idempotent and lock-aware; the consumer has no internal coordination between processes.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo