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

Symfony Messenger Auto Scale Laravel Package

krak/symfony-messenger-auto-scale

Automatically scale Symfony Messenger workers based on queue load, so you run only as many consumers as needed and save resources during quiet periods. A lightweight package for dynamic worker management.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require krak/symfony-messenger-auto-scale:^0.1.4

The package is a thin supervisor around messenger:consume: instead of a fixed numprocs=N in Supervisor, you run one scaler process per transport, and it spawns/terminates consumer child processes based on how many messages are actually sitting in the queue.

What v0.1.4 changes for you: the release notes are one line — "Support symfony 5 and 6." It's a compatibility widening, not a feature release. Nothing in the option names, YAML shape, command signature, or scaling semantics changed, so a 0.1.3 → 0.1.4 bump is operationally a no-op provided you're on Symfony 5.4 or 6.x. The flip side matters more: Symfony 7 is still not supported, so a Symfony 7 app cannot resolve this package at all. Treat it as "this pins your consumer sidecar to 6.4 LTS," and plan the Symfony 7 migration as a separate decision.

Where to look first

  1. vendor/krak/symfony-messenger-auto-scale/composer.json — confirm the actual symfony/messenger constraint before you plan an upgrade. "Supports 5 and 6" may mean ^5.0 || ^6.0 (which would let you run EOL 5.0–5.3) or ^5.4 || ^6.0; only the file knows.
  2. vendor/krak/symfony-messenger-auto-scale/src/ — identify the console command (bin/console list messenger will show it; bin/console messenger:auto-scale --help for its args) and the bundle class. If Flex didn't register it, add it to config/bundles.php.
  3. Any *.yaml in vendor/.../config/ or a DependencyInjection/Configuration.php — that file is the authoritative source for option names, defaults, and whether workers are configured per-transport or globally.
  4. README.md for the Supervisor snippet the author intended; copy it rather than inventing your own process-group settings.

If your day job is Laravel: this is a Symfony package, and Laravel already ships the equivalent — Horizon's balance: auto with minProcesses/maxProcesses, or queue:work under Supervisor with --max-jobs/--max-time. Reach for this one only in repos that genuinely run Symfony Messenger (mixed stack, shared internal bundle, Symfony sidecar consuming the same Redis/AMQP). Don't try to point it at Laravel queues; it reads MessageCountAwareInterface, not the Laravel queue API.

First use case

Point it at a bursty transport you'd normally over-provision — webhook delivery, image thumbnailing, PDF generation, outbound email — something that is idle overnight and backs up at 9am. Keep your latency-critical or low-volume queues on plain messenger:consume under Supervisor; migrating those gains nothing and adds a moving part.

Minimal shape (verify key names against the package's Configuration.php):

# config/packages/messenger_auto_scale.yaml
messenger_auto_scale:
    transports:
        async_burst:
            min_workers: 1
            max_workers: 16
; supervisor: ONE process for the scaler, not N consumers
[program:messenger-autoscale]
command=php %(ENV_APP_ROOT)s/bin/console messenger:auto-scale async_burst --env=prod
numprocs=1
stopasgroup=true
killasgroup=true
stopwaitsecs=60
autorestart=true

Implementation Patterns

Replace numprocs, don't stack on top of it. The scaler owns child lifecycle. Running both a static numprocs=8 consumer group and the scaler on the same transport means you're double-consuming and the scaler can never reach min_workers=0.

Fast up, slow down. Whatever the package calls it — cooldown, scale-down delay, interval — tune the two directions asymmetrically. Scale-up can react within a poll or two; scale-down should require sustained emptiness (30–60s) so you don't kill a worker mid-burst just because the queue drained momentarily.

Let children recycle themselves. Pass --time-limit=3600 --memory-limit=128M through to the consumers so long-lived workers exit cleanly and get replaced — this is the standard Messenger memory-leak defence and it composes well with a scaler that is already restarting processes. Both flags exist on messenger:consume across the 5.4 and 6.4 range v0.1.4 targets, so the same command line works whichever LTS you're on. If the scaler doesn't accept pass-through args, wrap messenger:consume in a two-line shell script and point command-style config at that.

One scaler per transport group. Don't ask a single process to manage every transport in the app; you want independent failure domains and independent min/max tuning (a min_workers: 0 queue should be able to sleep while a min_workers: 2 queue stays hot).

In Kubernetes, skip it. The scaler is a single-host Supervisor substitute. On K8s use KEDA's queue-length trigger against the same transports and let the Deployment controller do the work — you get the metrics, health checks, and rolling restarts for free. Use this package where you actually have Supervisor/systemd (single VPS, bare metal, some ECS-on-EC2 setups).

Observability: wrap the scaler's log output with a Monolog channel, and emit a gauge (current worker count per transport) to StatsD/Prometheus on each scaling decision. Without that gauge the scaler is a black box — you can't tell "scale-up is working" from "we're just permanently pinned at max_workers."

Testing the decision logic: the scaling policy is pure arithmetic on (messageCount, currentWorkers, elapsed). If the package exposes the policy as a service or interface, unit-test it with a fake count instead of trying to integration-test forked processes. v0.1.4 adds no such interface, so if it wasn't there before, assume it still isn't.

Gotchas and Tips

  • Symfony 7 is a hard wall, not a warning. Because 0.1.4 caps at Symfony 6, composer update on an app bumping to 7.x will fail resolution on this package. Decide now: stay on 6.4 LTS for the affected service, fork the constraint and test, or replace the package. Don't discover this mid-upgrade.
  • "Supports Symfony 5" can mean EOL Symfony 5. 5.4 is the only 5.x line worth running; if the constraint is looser than ^5.4, your own composer.json should still hold you at 5.4 (or, better, 6.4). Symfony 6 also raises your PHP floor to 8.1 — relevant if the same host runs older PHP services.
  • The signal is TransportInterface::getMessageCount() — only transports implementing MessageCountAwareInterface work. Doctrine and Redis are fine. Amazon SQS returns an approximate count and costs an API call per poll. Beanstalkd is approximate. sync:// and null:// cannot be counted at all and will silently never scale.
  • AMQP prefetch destroys the signal. With prefetch_count=10 and 5 workers, the broker hands 50 messages to clients immediately, so getMessageCount() reads ~0 while your workers are 100% saturated. Auto-scaling on queue depth is wrong for AMQP-with-prefetch; use it on Doctrine/Redis transports, or keep AMQP prefetch low and accept that scaling reacts to broker-visible backlog only.
  • getMessageCount() is not free. Every poll is a SELECT COUNT(*) on the messenger table (or a Redis LLEN, or an SQS API round-trip). A 1-second interval across several transports is meaningful DB load. Set the poll interval to 5–15s in production.
  • Orphaned workers on scaler death. If the parent is SIGKILLed, children can survive and you get zombie consumers. stopasgroup=true + killasgroup=true in Supervisor is not optional; also verify the package forwards SIGTERM to children rather than exiting immediately.
  • POSIX only, almost certainly. Process spawning via proc_open/pcntl means no Windows, and it cannot be driven from a web request or a short-lived command — it's a foregone-conclusion long-running process.
  • Cold-start lag is your real SLA. A scaling decision at T triggers a process spawn; by the time a Symfony container boots and the worker connects, 1–3 seconds have passed (more if the container is heavy). Size min_workers for your baseline traffic, not for zero.
  • Upgrading 0.1.3 → 0.1.4 is safe and boring. No config migration, no renamed options per the release notes. Bump it, keep the Supervisor unit as-is, and smoke-test one scale-up/scale-down cycle on a non-critical transport before rolling it everywhere.
  • Still pre-1.0, single-maintainer, low visibility. 0.1.4 is a compatibility bump, not a sign of renewed investment — no process-management changes, no policy abstraction, no Symfony 7 roadmap in the notes. Pin the exact version ("krak/symfony-messenger-auto-scale": "0.1.4") so a future tag can't silently change consumer behaviour, and keep the ~100-line custom command wrapping messenger:consume in your back pocket; it's the only part you can't easily replace.
  • Extension points to check for: a ScalePolicy/Scaler interface (swap in a latency-based or rate-based policy instead of raw queue depth) and the worker-pool/process abstraction (swap proc_open for Symfony Process). v0.1.4 doesn't advertise either, so treat the package as a black box and evaluate it purely on the command's operational behaviour.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast