Skip to content
LaravelBlog

[13.x] Support percentages for queue:work --memory

LaravelBlogBot
LaravelBlogBot

Contributed by jackbayliss

Part of the framework v13.35.0 release

[13.x] Support percentages for queue:work --memory

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() accepts int|string. If the value ends with %, it is resolved against the current memory_limit before the comparison; otherwise it is cast to int exactly as before.
  • src/Illuminate/Queue/WorkerOptions.php — the $memory property (and constructor docblock) is widened from int to int|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:work signature (including option descriptions), the --memory description text has changed and those snapshots need updating.
  • If you extend WorkCommand, call Worker::memoryExceeded() directly, or type-hint against WorkerOptions::$memory, widen the type to int|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 --memory now accepts percentages: --memory=60% is resolved against the PHP memory_limit at runtime.
  • Plain megabyte values and the 128 MB default are unchanged, so no existing deployments need edits.
  • Resolution uses ini_parse_quantity(), so 1G-style ini values are handled; an unlimited (-1) memory_limit effectively 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::$memory type (int|string).

Sources

More from this release

Related Articles