[13.x] Support percentages for queue:work --memory
Contributed by jackbayliss
Part of the framework v13.35.0 release
Category: 2 (Feature)
Pull request #61753 lets the queue:work --memory option accept a percentage of the PHP memory_limit in addition to an absolute number of megabytes. Instead of hardcoding --memory=2048 and manually recalculating it every time your containers are resized, you can now write --memory=60% and have the worker's memory ceiling scale automatically with whatever memory_limit the runtime is configured with. The change is small and fully backwards compatible: plain megabyte values behave exactly as before, and the default of 128 MB is untouched.
What changed
Three files carry the feature:
src/Illuminate/Queue/Console/WorkCommand.php— the option's description now reads "The memory limit in megabytes, or as a percentage of the PHP memory limit".src/Illuminate/Queue/Worker.php—memoryExceeded()acceptsint|string. If the value ends with%, it is resolved against the currentmemory_limitbefore the comparison; otherwise it is cast tointexactly as before.src/Illuminate/Queue/WorkerOptions.php— the$memoryproperty (and constructor docblock) is widened frominttoint|string.
A regression test was added covering the percentage path, and the command-signature fixture used by the test suite was updated to reflect the new description text.
Using it
The new syntax is a single flag change:
# Absolute limit — unchanged behavior
php artisan queue:work redis --memory=512
# Percentage of the PHP memory_limit
php artisan queue:work redis --memory=60%
So if a container runs PHP with memory_limit=2G, this worker will gracefully stop (rather than die on a fatal out-of-memory error) once its real memory usage reaches roughly 1228 MB:
php -d memory_limit=2G artisan queue:work --memory=60%
How percentages are resolved
Inside memoryExceeded(), a value like 60% is converted to megabytes using PHP's native ini_parse_quantity():
$memoryLimit = str_ends_with((string) $memoryLimit, '%')
? ini_parse_quantity(ini_get('memory_limit')) / 1024 / 1024 * ((float) $memoryLimit / 100)
: (int) $memoryLimit;
return $memoryLimit > 0 && $this->currentMemoryUsage() >= $memoryLimit;
ini_parse_quantity() understands ini shorthand like 512M, 1G, or 1024K, so it handles any valid memory_limit format. The result is compared against the worker's current usage (reported in MB), and the final > 0 guard preserves the existing "disabled" semantics: if memory_limit is -1 (unlimited) the resolved limit comes out negative, so the check simply never trips — same as passing 0 today.
The new test illustrates the math concretely: with memory_limit=1G and a fake usage of 512 MB, memoryExceeded('50%') returns true (512 ≥ 512) while memoryExceeded('51%') returns false.
Why this matters
The motivating scenario is worker resizing. When your platform team scales a queue container up or down, memory_limit moves with it — but --memory was a static number someone had to recalculate by hand. Forget to update it and you get the worst of both worlds: a raised memory_limit with a stale worker limit that throttles throughput, or a lowered one where the OS OOM-killer or a PHP fatal error takes the worker down instead of Laravel's graceful stop-and-restart.
With a percentage, the worker limit tracks the container automatically. It's also convenient locally: --memory=50% behaves sensibly on a modest laptop and on a beefy workstation alike, where a hardcoded --memory=4096 might mean nothing or everything depending on the machine.
One deliberate note from the PR: this doesn't affect Laravel Cloud managed queues, since they don't accept custom worker options — and as a general practice you shouldn't push the percentage to 100% anyway. The whole point is for the worker to exit cleanly before PHP hits its own limit, so leave headroom (50–75% is a reasonable band).
Upgrade impact from v13.34.0
There is no breaking change. Passing an integer — e.g. --memory=256 — resolves through the same (int) path as before, and the default remains 128. Two minor things to check when you upgrade:
- If any of your own tests assert the full
queue:worksignature (including option descriptions), the--memorydescription text has changed and those snapshots need updating. - If you extend
WorkCommand, callWorker::memoryExceeded()directly, or type-hint againstWorkerOptions::$memory, widen the type toint|string.
Programmatic usage works with either form:
use Illuminate\Queue\WorkerOptions;
new WorkerOptions(
name: 'default',
memory: '60%', // or 512, both are valid now
);
Takeaways
queue:work --memorynow accepts percentages:--memory=60%is resolved against the PHPmemory_limitat runtime.- Plain megabyte values and the 128 MB default are unchanged, so no existing deployments need edits.
- Resolution uses
ini_parse_quantity(), so1G-style ini values are handled; an unlimited (-1)memory_limiteffectively disables the check. - The big win is infrastructure: resize a container, bump
memory_limit, and worker limits follow without recalculation or redeploys. - Only cosmetic upgrade notes: updated help text and a widened
WorkerOptions::$memorytype (int|string).