Kennedy Mutisya
Common Issues That Cause Laravel Queue Workers Not to Restart
Diagnose why `php artisan queue:restart` is ignored by workers and fix cache drivers, prefixes, and process modes.
Restarting queue workers should be a standard part of your deployment script. The command is simple:
php artisan queue:restart
It works by writing an illuminate:queue:restart key to your cache store with a timestamp. Workers check this key after finishing each job. If the timestamp is newer than when they last checked, the worker process exits gracefully, and your process manager starts a fresh one.
If you are using Laravel Forge, you can check a worker's uptime. After a successful restart, you will see something like:
worker-:worker-_00 RUNNING pid 75, uptime 0 days, 00:00:20
That is a brand new process. If the worker's uptime is much longer than expected after you ran queue:restart, something is preventing the restart. Here are the usual culprits.
1. The Worker Is Running in Listen Mode
If you started the worker with queue:listen instead of queue:work, the listener spawns a separate child process for every job. Once the job finishes, the child process is killed and a new one is created for the next job. This means every job already runs with the latest code. The listener has no persistent state to clear, so queue:restart has zero effect on it.
The only way to restart a listener process is manually:
supervisorctl restart worker-name:*
If you are relying on queue:restart and wondering why nothing happens, check whether your workers are running in listen mode versus daemon mode.
2. The Cache Store Is Not Shared or Accessible
For queue:restart to work, every worker process needs to read from the same cache store where the restart timestamp is written. If your workers are on different machines or different cache configurations, they will not see the key.
A common variant: the queue:restart command writes the key using one cache driver, but the workers read from another. Both sides need to agree on the same CACHE_DRIVER and the same backend (same Redis database, same Memcached server, same filesystem).
File cache driver gotcha: If you are using the file cache driver, the user running queue:restart must be able to write the cache file, and the user running the worker processes must be able to read it. Permission issues here will silently break the restart:
sudo chown -R forge:forge storage/framework/cache
This ensures the cache directory is owned by the forge user. If both the deploy script and the workers run as forge, everything works.
3. The Cache Prefix Changed
If you change the cache prefix in config/cache.php (or via CACHE_PREFIX), the restart command writes the illuminate:queue:restart key under the new prefix. Existing workers still look for the key under the old prefix. They never see the updated timestamp, so they never restart.
This is a one-time problem. After you change the prefix, you need to restart the workers manually once to pick up the new prefix:
supervisorctl restart worker-name:*
After that manual restart, subsequent queue:restart calls work normally because all processes now share the same prefix.
How queue:restart Actually Works
When you run queue:restart, Laravel updates the illuminate:queue:restart timestamp in the cache to the current time.
Inside the worker daemon loop, stopIfNecessary() runs after each job and calls queueShouldRestart():
protected function stopIfNecessary(WorkerOptions $options, $lastRestart)
{
if ($this->shouldQuit) {
$this->kill();
}
if ($this->memoryExceeded($options->memory)) {
$this->stop(12);
} elseif ($this->queueShouldRestart($lastRestart)) {
$this->stop();
}
}
queueShouldRestart() compares the stored $lastRestart timestamp (captured when the worker started) against the current value of the illuminate:queue:restart cache key. If the cached value is newer, the worker knows a restart was requested and exits.
The worker will not exit in the middle of processing a job. The check only happens between jobs. Once the current job finishes, the worker sees the new timestamp and stops. Supervisor detects the stopped process and starts a replacement.
Key Takeaways
queue:restartonly works withqueue:work(daemon mode), notqueue:listen.- Workers must share the same cache store as the process running
queue:restart. - File cache permissions can silently prevent restarts. Check ownership of
storage/framework/cache. - Changing the cache prefix requires one manual restart to sync workers.
- The worker exits between jobs, not in the middle of one, so no jobs are lost during a restart.