Upgrading to v4
Upgrading to v4
Most applications upgrade by raising PHP to 8.4, renaming one configuration key and deleting another. The list below is complete rather than short — everything that can break is here, including the parts that will not affect you.
Start with the check command, which reads your configuration against the queues you actually have:
composer require cboxdk/laravel-queue-autoscale:^4.0
php artisan queue:autoscale:doctor
Requirements
PHP 8.4 is now the minimum, and Laravel 11 is no longer supported. If you are on PHP 8.3 or Laravel 11, upgrade those first — v3 runs on both and there is no rush to move.
| v3 | v4 | |
|---|---|---|
| PHP | 8.3, 8.4, 8.5 | 8.4, 8.5 |
| Laravel | 11, 12, 13 | 12, 13 |
The worker timeout is now two settings
This is the change most likely to affect you, and the one most likely to have been quietly wrong before.
In v3, workers.timeout_seconds was passed to queue:work as --max-time — the worker process's
lifetime. It was never a job timeout, despite reading like one. An operator setting 3600 believed
they had allowed hour-long jobs; what they had actually done was recycle the worker hourly while jobs
still died at Laravel's default timeout.
The two are now separate:
'workers' => [
'max_time_seconds' => 3600, // --max-time: recycle the worker process this often
'timeout_seconds' => 900, // --timeout: how long a single job may run
],
What to do: rename timeout_seconds to max_time_seconds everywhere it appears in your config
and in any custom profile. Then decide what your job timeout should be — the new timeout_seconds
defaults to 900 seconds, and configuration will refuse a job timeout that is not shorter than the
process lifetime, because a job allowed to outlive its own worker can never finish.
The global workers block is gone
v3 had two places to configure workers: a global queue-autoscale.workers block and a per-queue
workers key. Only the global one reached a spawned worker, so tries, sleep_seconds and
shutdown_timeout_seconds set on a profile were parsed, validated, and ignored.
The profile is now the only surface, and what a queue declares is what its workers run with.
What to do: delete the top-level 'workers' => [...] block from config/queue-autoscale.php. If
it held values you relied on, move them into sla_defaults or into the profiles that need them —
they will now actually take effect, which may itself be a change in behaviour worth watching.
One key moved rather than being deleted: workers.shutdown_timeout_seconds is now
manager.shutdown_grace_seconds, and it is a fallback for workers whose queue configuration can no
longer be resolved — not a floor. A pool of fast queues no longer waits for the slowest global
setting.
Metric names
The package publishes cluster metrics on two surfaces — the clusterMetrics() facade method and the
telemetry gauges — and they disagreed about five names. They now agree. If you scrape either, update
your queries:
| v3 | v4 |
|---|---|
queue_autoscale_cluster_hosts_recommended |
queue_autoscale_cluster_recommended_hosts |
queue_autoscale_cluster_workers_current |
queue_autoscale_cluster_workers |
queue_autoscale_cluster_workers_required |
queue_autoscale_cluster_required_workers |
queue_autoscale_cluster_capacity |
queue_autoscale_cluster_worker_capacity |
queue_autoscale_manager_workers |
queue_autoscale_cluster_host_workers |
queue_autoscale_manager_capacity |
queue_autoscale_cluster_host_capacity |
queue_autoscale_manager_cpu_percent |
queue_autoscale_cluster_host_cpu_percent |
queue_autoscale_manager_memory_percent |
queue_autoscale_cluster_host_memory_percent |
A dashboard querying an old name returns no data rather than an error, which looks identical to the metric reading zero — so this is worth doing before you deploy, not after.
The cluster store is behind a contract
ClusterStore now implements ClusterStoreContract, and everything in the package depends on the
contract. If you resolved ClusterStore::class from the container directly it still works, but
prefer the contract — and if you decorated or swapped the concrete class, bind
ClusterStoreContract::class instead.
Deleted classes
Cbox\LaravelQueueAutoscale\Workers\ProcessHealthCheck— worker liveness is checked inline in the evaluation cycle. Nothing referenced it.Cbox\LaravelQueueAutoscale\Output\DataTransferObjects\JobActivity— unused output DTO.
New in v4, nothing to do
These are additive. Listed so you know they exist:
- Queue patterns.
queue-autoscale.queuesaccepts glob keys, soscrape-tenant-*can govern every tenant queue at once. Exact names still win over patterns. See Respect a Per-Tenant Connection Limit. - Queue names with dots now reach their config.
config('queue-autoscale.queues.tenant.42')split on the dots, so a queue literally namedtenant.42— or any.fifoqueue — silently ran on defaults. If you have such a queue, its configuration will start applying on upgrade. That is the fix working, but it is a behaviour change: check the doctor output. profilealongside overrides. A queue entry can name a profile and refine it, instead of restating every field.ConnectionLimitedProfilefor queues whose parallelism is dictated by something downstream.queue:autoscale:doctor— see Check Your Configuration.src/Testing— fakes and assertions for testing your own configuration. See Testing Your Configuration.- Pickup sampling. Above 100 recorded pickups per second per worker process, a uniformly random
subset is stored instead of every one. Enabled by default; it costs nothing in accuracy because the
store only ever retained a bounded number of samples anyway. Disable with
QUEUE_AUTOSCALE_PICKUP_SAMPLING=false.
Checklist
- PHP 8.4+ and Laravel 12+
-
workers.timeout_secondsrenamed tomax_time_seconds, and a job timeout chosen - Top-level
'workers'block deleted from the config -
workers.shutdown_timeout_secondsmoved tomanager.shutdown_grace_secondsif you set it globally - Dashboards and alerts updated for the renamed metrics
-
php artisan queue:autoscale:doctorrun and its output read — it flags both of the configuration changes above if you miss them