webparking/laravel-queue-garbage-collection

Collect PHP reference cycles after every queue job to keep long-running workers from leaking off-heap memory.
1,026
Install
composer require webparking/laravel-queue-garbage-collection
Latest Version:v1.0.0
PHP:^8.1
License:MIT
Last Updated:Jul 6, 2026
Links: GitHub  ·  Packagist
Maintainer: webparking

Collect garbage cycles after every queue job

Latest Version on Packagist Total Downloads run-tests

A zero-config Laravel package that runs gc_collect_cycles() after every queue job.

Why this exists

Long-running queue workers accumulate PHP reference cycles that pin off-heap memory: the native buffers behind libcurl and OpenSSL (any HTTP client or SDK), DOM trees, image resources, and similar extension-backed objects. That memory is invisible to memory_get_usage(), so queue:work --memory never trips on it. Meanwhile PHP's adaptive cyclic garbage collector backs off precisely in this situation — the cycles hold only a handful of PHP objects while pinning a lot of native memory, so the collector's object-count heuristic sees nothing worth collecting. The result: resident memory (RSS) climbs job after job until the worker is OOM-killed.

Forcing a collection at each job boundary releases those cycles immediately and keeps memory flat. It is safe to force per job because queue workers share no state between jobs, so nothing you'd want to keep is ever collected.

Installation

composer require webparking/laravel-queue-garbage-collection

That's it. The service provider auto-registers via Laravel's package discovery and hooks a listener onto both JobProcessed (success) and JobExceptionOccurred (each failed attempt). The listener calls gc_collect_cycles() and nothing else.

When you might not want it

The only profile where this is pure overhead is a very high-throughput queue of tiny, cycle-free jobs under no memory pressure — there, each collection scans the GC root buffer and frees nothing. Everywhere else the cost is negligible, and it is never a correctness risk (workers share no state across jobs, so a forced collection can only reclaim genuine garbage).

Supported versions

Every combination below is exercised in CI:

PHP Laravel Testbench
8.1 9 7
8.2 10 8
8.3 11 9
8.4 12 10
8.5 13 11

Testing & local development

The full PHP × Laravel matrix runs locally via act, executing the exact CI workflow in Docker:

make test               # run the whole matrix (needs `act` + Docker)
make test-job php=8.3   # run a single PHP version from the matrix

For day-to-day work there's a Docker workspace pinned to the newest supported combination (PHP 8.5 / Laravel 13):

make start     # start the workspace and install dependencies
make phpunit   # run the test suite once
make phpstan   # run static analysis
make cs-fix    # apply code style
make help      # list all targets

Prefer running things yourself? composer install && composer test works too.

License

The MIT License (MIT). Please see the License File for more information.

Related Packages

maqe/laravel-sqs-fifo

Laravel package that enables support for SQS FIFO Queue

141,184 15
ytake/laravel-couchbase

Couchbase providers for Laravel

52,512 30
bschmitt/laravel-amqp

AMQP wrapper for Laravel and Lumen to publish and consume messages

2,756,595 281
yozaz/laravel-swiftmailer

Laravel and SwiftMailer integration fix for Queued deamon workers

73,940 24
spatie/laravel-failed-job-monitor

Get notified when a queued job fails

3,053,158 1,057