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

Busque Laravel Package

mgdigital/busque

Busque is a lightweight command bus for Laravel that maps commands to dedicated handlers, keeping controllers and services thin. It supports middleware pipelines and queued command execution, making it easy to organize complex application logic with a clean, testable CQRS-style approach.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements first, not code. Busque is PHP 7–era, built on ext-pcntl/ext-posix and a Redis store accessed through Predis. It will not run on Windows or PHP 8, and the repo is archived — treat it as a stable black box, not something you can patch.

composer require mgdigital/busque predis/predis

Where to look first (in this order):

  1. README.md — the enqueue + worker example is the whole mental model.
  2. src/Busque.php — the facade; every entry point (enqueue, startWorker, startSupervisor, failed-job helpers, scheduler) lives here. Read the method signatures, not the docs, since the README lags the code.
  3. src/Job/JobInterface.php — the contract you implement.
  4. src/System/Worker.php and src/System/Supervisor.php — how forking, respawning, and failure are actually handled.
  5. src/Configuration/QueueConfiguration.php — the knobs you'll tune under load.

First use case — a job class plus an enqueue call:

use Busque\Job\JobInterface;

class SendInvoiceEmail implements JobInterface
{
    public function perform(array $args)
    {
        // Throwing = failure. Returning silently = success.
        \App\Invoice::findOrFail($args['invoiceId'])->send();
    }
}

$redis  = new \Predis\Client(['host' => '127.0.0.1', 'port' => 6379]);
$busque = new \Busque\Busque($redis);

$busque->enqueue('emails', new SendInvoiceEmail(), ['invoiceId' => 42]);

First worker. Do not run this from a web request. Put it behind a console command or a shell script, and start with a single process in the foreground so you can see output:

php bin/busque-worker.php   # calls $busque->startWorker('emails', 1)

Confirm the job runs, then move to startSupervisor() under systemd/supervisord for multi-process production.

Implementation Patterns

Laravel wiring (there is none built in). Bind Busque as a container singleton around a shared Predis client, and expose console commands:

$this->app->singleton(\Busque\Busque::class, function () {
    return new \Busque\Busque(new \Predis\Client(config('database.redis.default')));
});

Then three artisan commands: busque:work {queue}, busque:supervise {queue}, busque:scheduler. Register them in the scheduler or process manager — never invoke them from HTTP.

One queue per work class. This is the single biggest lever. Long-running report jobs, quick email jobs, and webhook retries should never share a queue; a slow job blocks the whole pipeline. Then run a supervisor per queue with a concurrency tuned to that queue's memory profile.

Payload discipline. Jobs are PHP-serialize()d into Redis. Pass scalars and IDs, not Eloquent models or large arrays. A fat job payload is both a Redis memory cost and a slow unserialize on every worker pickup.

Delayed work. Busque supports scheduled jobs via a sorted set drained by Busque\Scheduler\Scheduler. You must run the scheduler process — enqueue-with-delay without a running scheduler means the job sits in Redis forever and looks like a "lost job." Run exactly one scheduler.

Failure handling as a first-class loop. Failed jobs land back in Redis with their exception trace. Build an artisan command over getFailedJobs() / requeueFailedJob($id) / deleteFailedJob($id) so you're not dropping into redis-cli at 2am. Retry the requeue from a dashboard, not by re-enqueuing manually (you lose the original args otherwise).

Deployment. Workers load your code at boot and keep it in memory. After every deploy, gracefully SIGTERM the supervisor, let in-flight jobs finish, then restart. If you skip this, old code keeps running against new DB schemas.

Monitoring. Queue depth is just Redis (LLEN/ZCARD against the queue's keys — inspect with redis-cli KEYS '*<queue>*' once to learn the exact naming). Push depth, failed count, and worker heartbeat into your metrics stack; Busque gives you no UI.

Gotchas and Tips

  • Archived means frozen. No PHP 8 support, no security patches. New greenfield work should use Laravel Horizon or Symfony Messenger; keep Busque only for existing queues you're not ready to migrate. Budget for that migration.
  • Predis only. If you pass a phpredis \RedisInstance (or any ClientInterface mismatch), you'll get type errors deep inside the worker. Match the client the package expects; don't swap drivers for "performance" without reading Busque.php first.
  • perform() semantics are silent. An uncaught exception is a failure; a swallowed exception is a success and the job is gone. Never wrap perform() bodies in try/catch that returns normally unless you truly want the job dropped.
  • Serialization couples web and worker. Same code release, same autoloader, same PHP minor version on both sides. A renamed class breaks every queued job until you drain or clear the queue.
  • Long-lived workers leak. PHP doesn't reset between jobs. Watch RSS; use QueueConfiguration to retire workers after N jobs, and reconnect to the DB inside perform() if you hold persistent connections — forked children inherit the parent's socket and can corrupt it.
  • Forked children and stdout. With multiple processes, log lines interleave. Log to a file or syslog with the PID, not echo, or you'll be unable to trace which child failed.
  • Queue name typos are silent. A misspelled queue string enqueues fine and is simply never consumed. Add an assertion or a config constant for queue names rather than string literals scattered across the codebase.
  • Redis durability is your durability. Default Redis has no persistence. If the box dies, queued jobs are gone. Enable AOF if the work matters; document that Busque is a queue, not a ledger.
  • Debugging approach. Run one worker in the foreground with verbose output, redis-cli MONITOR to watch pushes/pops, and inspect the failed set directly. Nine times out of ten the bug is a payload that unserializes differently than it was enqueued.
  • Extension points are thin but real. QueueConfiguration for concurrency/retry tuning, subclassing Supervisor for custom respawn policy, and wrapping Busque in your own service to add tracing/job middleware are the practical ones — there's no event system to hook.
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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels