Skip to content

Laravel queue:work Now Prints Why the Worker Stopped

Laravel 13.30 adds a stop-reason line to queue:work output. Workers now print why they exited—memory limit, restart signal, job timeout, and more—in both plain and JSON formats.

Published · Updated · 3 min read

Laravel queue:work Now Prints Why the Worker Stopped

What Changed in Laravel 13.30

Before Laravel 13.30, a queue:work process could exit for nine different reasons and the console output looked identical every time. If a worker managed by Supervisor restarted every few minutes, you had no quick way to tell whether it hit its memory limit, lost its database connection, or picked up a queue:restart signal from a deploy. You had to register an event listener or correlate the restart time against a deploy log.

Starting with Laravel 13.30, the worker prints a human-readable reason on its last output line:

2026-09-01 13:20:40 Worker STOPPED Memory limit exceeded

Contributed by Jack Bayliss in PR #61339.

Console and JSON Output

WorkCommand now registers a listener for the WorkerStopping event alongside the existing job and queue status listeners. The stop line appears in the same two formats as the rest of the output.

With --json, the stop reason is a structured record:

{"level":"info","status":"stopped","reason":"empty","exit_code":0,"jobs_processed":12,"memory":34.0,"timestamp":"2026-09-01T13:20:40.118273+00:00"}

Key fields to know:

  • reason — the enum's backing value; stable to match on in scripts or log queries.
  • memory — megabytes rounded to one decimal, or null when no figure was recorded.
  • level — info for exit code 0, warning for anything else.

The stop line is suppressed under --quiet and --silent, and when the reason is null. Workers killed by an OOM killer or SIGKILL never reach the event dispatch code, so those exits remain silent.

All Nine Stop Reasons

WorkerStopReason is an existing enum. This change added a description() method to it so the console output and any listener you write share the same strings.

| Value | Description | Exit code | |---|---|---| | empty | Queue empty | 0 | | empty_for | Queue empty for the configured duration | 0 | | max_jobs | Maximum jobs exceeded | 0 | | max_time | Maximum run time exceeded | 0 | | restart_signal | Received restart signal | 0 | | interrupted | Interrupted | 0 | | lost_connection | Lost connection | 0 | | memory | Memory limit exceeded | 12 | | timed_out | Job timed out | 1 |

Filtering JSON Output with jq

Because the reason is now a discrete field, isolating stop events from a long log stream is a one-liner:

php artisan queue:work --json --max-time=3600 2>&1 | \
    jq -c 'select(.status == "stopped")'

Under a process manager writing to a file, the same jq query runs against the log after the fact.

Using the WorkerStopping Event

For anything beyond reading output—dashboards, metrics backends, alerting—the WorkerStopping event is still the right hook. It carries the reason, exit status, jobs processed, last-job timestamp, and memory in use:

use Illuminate\Queue\Events\WorkerStopping;

Event::listen(function (WorkerStopping $event) {
    Log::info('Worker stopped', [
        'reason'  => $event->reason?->value,
        'status'  => $event->status,
        'jobs'    => $event->jobsProcessed,
        'memory'  => $event->memoryUsage,
    ]);
});

Use it to count exits per reason for a dashboard or push each one into a metrics backend.

Key Takeaways

  • queue:work now prints a stop-reason line in both plain and --json output as of Laravel 13.30.
  • Nine stop reasons are defined on the WorkerStopReason enum; each has a stable backing value and a new description() method.
  • The reason field in JSON output is safe to match on in scripts and log queries.
  • Workers killed by SIGKILL or an OOM killer remain silent—the event never fires in those cases.
  • The WorkerStopping event is still the best integration point for dashboards and metrics.

Source: Laravel queue:work Now Prints Why the Worker Stopped — Laravel News

Frequently asked questions

Why does my Laravel queue:work process restart silently with no output?

Before Laravel 13.30, all nine stop reasons produced identical output, making it impossible to distinguish a memory limit hit from a restart signal or a lost database connection at a glance. Upgrading to 13.30 adds a stop-reason line to the last line of output, and a `reason` field to the `--json` format, so you can see exactly why the worker exited.

Will the stop reason appear if my worker is killed by an OOM killer or SIGKILL?

No. A worker killed externally by an OOM killer or a SIGKILL never reaches the code that dispatches the WorkerStopping event, so those exits remain silent. The stop-reason line only appears for the nine reasons tracked internally by the framework.

How can I programmatically react to specific queue worker stop reasons?

Listen to the `Illuminate\Queue\Events\WorkerStopping` event. It exposes `$event->reason?->value` (the stable enum backing value), `$event->status` (exit code), `$event->jobsProcessed`, and `$event->memoryUsage`. Use it to send metrics, trigger alerts, or log structured data to a dashboard.

Mohamed Said

About the author

Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

About GitHub LinkedIn WhatsApp Email Address My CV

Have a technical challenge?

Tell me what you’re building. I reply within two working days.

Discuss your project