mcfedr/queue-manager-bundle
A Symfony bundle for managing queue jobs, giving you a web interface and commands to inspect, retry, and delete failed or pending messages across your queues.
First, a stack check. mcfedr/queue-manager-bundle is a Symfony bundle: it ships a Bundle class, Doctrine entities, DI service definitions, and console commands. It is not a Laravel package — there is no service provider, no config/queue.php driver, and no Horizon integration. In a pure Laravel app you cannot just composer require it and have php artisan queue:work pick up jobs. Decide which mode you are in before writing any code:
Minimal steps in a Symfony host:
composer require mcfedr/queue-manager-bundle
Mcfedr\QueueManagerBundle\McfedrQueueManagerBundle in config/bundles.php.config/packages/mcfedr_queue_manager.yaml.Where to look first: the bundle README's config reference, the JobManager service (the dispatch entry point), the Job entity (status/params/result/timestamps), the handler interface, and the worker command. If Laravel needs to inspect job state, also look at mcfedr/queue-manager-rest-bundle — an HTTP surface is usually a cleaner contract than sharing a database.
First use case: a slow operation you don't want in a Laravel request — image derivatives, PDF/report export, third-party sync. Laravel records intent (a local remote_jobs row with the returned job id), the Symfony worker executes it, and Laravel reconciles status.
// Symfony side: one handler per queue
final class ThumbnailHandler implements JobHandler
{
public function handle(Job $job): void
{
$params = $job->getParams(); // keep these scalar: ids, paths
// ... do the work, idempotently
}
}
// Laravel side: wrap the integration in a client + queued job
final class DispatchRemoteJob implements ShouldQueue
{
public function handle(RemoteQueueClient $client): void
{
$jobId = $client->create('thumbnails', ['image_id' => $this->imageId]);
RemoteJob::create([
'remote_id' => $jobId,
'queue' => 'thumbnails',
'status' => 'pending',
]);
}
}
Job id in the message, state in the DB. The bundle's model is the one worth copying even if you never install it: the broker message is a pointer (job id/queue), and the row holds params, status, start/finish times, and result. That gives you visibility, reruns, and debugging that a raw serialized payload doesn't. Mirror this in Laravel with a remote_jobs table rather than stuffing payloads into the broker.
Handler-per-queue mapping. Keep one handler service per queue name and keep the mapping explicit in config. Do not multiplex by params (if ($params['type'] === ...)) — it makes routing opaque and reruns ambiguous.
Three integration shapes, in order of preference:
RemoteQueueClient) with create/status/cancel. Version the payload, sign requests, retry with backoff. Cleanest boundary; no shared schema.Worker deployment. Treat the Symfony worker like a Laravel queue worker: one long-running process per queue or driver, supervised, restarted on deploy, logs shipped to the same place as your Laravel logs. If the command supports a max-jobs/time-limit option, use it so workers recycle — long-running PHP processes leak memory.
Status reconciliation. Add a scheduled Laravel command that polls non-terminal remote_jobs and updates local state, with jitter and backoff. Don't poll in the request cycle. If the bundle supports callbacks/webhooks, prefer them and keep polling as a safety net.
Porting the pattern to Laravel. If the goal is the behavior rather than the package: RemoteJob model, a DispatchRemoteJob queued job, a worker command that claims rows with SELECT ... FOR UPDATE SKIP LOCKED, idempotent handlers keyed by queue name, and failed_jobs-style dead-letter visibility. That is a weekend of work and removes the cross-framework dependency.
Local development. Run the Symfony worker as a container alongside Laravel in docker-compose, and use the Doctrine driver locally for zero broker infrastructure, then switch to AMQP/SQS in staging. Keep the driver choice in env, not in committed config.
php artisan surface. queue:work, queue:retry, queue:failed, and Horizon will not see these jobs. Your operational runbooks need Symfony-side equivalents or a wrapper.failed_jobs table gives you none of this.How can I help you explore Laravel packages today?