Current Behavior
After composer install pulls in a Laravel 12 illuminate/queue (currently ^12.0), the flarum queue:work worker crash-loops on every pop. Every queue-poll iteration throws:
Error: Call to undefined method Flarum\Queue\QueueFactory::getPausedQueues()
in vendor/illuminate/queue/Worker.php:476
On our forum this manifested as 8,000+ identical error lines in the daily log and a queue worker that supervisor restarted every ~3 minutes for hours — no jobs processed, no notification emails sent during that window. Once the new illuminate/queue is in composer.lock, the worker cannot run.
Root Cause
Illuminate\Queue\Worker::getPausedQueues() (added in Laravel 12) was extended in a way that delegates to the queue manager:
// vendor/illuminate/queue/Worker.php (~L466)
protected function getPausedQueues($connectionName, $queues)
{
if (! static::$pausable) {
return [];
}
if ($this->cache === null) {
return [];
}
return $this->manager->getPausedQueues($connectionName, $queues); // ← fatal here
}
It is called unconditionally inside the worker's pop loop:
// vendor/illuminate/queue/Worker.php (~L437)
$paused = array_flip($this->getPausedQueues($connection->getConnectionName(), $queues));
Flarum binds \Illuminate\Contracts\Queue\Factory to Flarum\Queue\QueueFactory, which implements only the single connection() method that the contract requires. The Worker's $this->manager is that QueueFactory instance — it has no getPausedQueues(), no getRestartTimestamp(). Same root cause would surface for the $restartable path the next time it gets hit.
Steps to Reproduce
- Flarum 2.0-rc.1 (or any composer state that resolves
illuminate/queue ^12.x with the getPausedQueues Worker change).
- Configure a non-trivial queue driver (we use Redis, but
database/sync should reproduce the same fatal once polling fires).
php flarum queue:work (or any supervisor-managed worker) — the very first pop logs the fatal and exits, supervisor restarts, repeat.
Expected
Worker runs without fatals against the existing QueueFactory. Pause/restart polling is genuinely optional in Laravel 12 — it exists for php artisan queue:pause, which Flarum doesn't expose.
Suggested Fix
Use Laravel's own opt-out, Illuminate\Queue\QueueManager::withoutInterruptionPolling(), or equivalently flip the two static gates the Worker honours, in Flarum\Queue\Console\WorkCommand::handle():
public function handle()
{
\Illuminate\Queue\Worker::$pausable = false;
\Illuminate\Queue\Worker::$restartable = false;
// … existing handle() body …
}
This is the upstream-blessed opt-out — see QueueManager::withoutInterruptionPolling() at vendor/illuminate/queue/QueueManager.php:312, which does exactly:
public function withoutInterruptionPolling()
{
Worker::$restartable = false;
Worker::$pausable = false;
}
With these flags off, Worker::getPausedQueues() and the restart-cache check return early without ever touching $this->manager, so neither method needs to exist on QueueFactory. This also covers any future Laravel additions that gate behind $pausable/$restartable, which a per-method shim on QueueFactory wouldn't.
(An alternative is to shim getPausedQueues($connection, $queues) { return []; } on QueueFactory, but that's reactive — every future Laravel release that adds another manager-method behind the same flags would need a new shim.)
Environment
- Flarum 2.0-rc.1
- PHP 8.4 on Debian 12
illuminate/queue ^12 (just pulled by composer)
- Redis queue driver
- Supervisord-managed
flarum-queue worker
Additional Context
Discovered on production via 8,000+ flarum.ERROR entries in a single day's log. Workaround applied locally by setting the two statics in Flarum\Queue\Console\WorkCommand::handle(). Confirmed worker stable past the previous 3-minute crash interval; backlog drained.
Current Behavior
After
composer installpulls in a Laravel 12illuminate/queue(currently^12.0), theflarum queue:workworker crash-loops on every pop. Every queue-poll iteration throws:On our forum this manifested as 8,000+ identical error lines in the daily log and a queue worker that supervisor restarted every ~3 minutes for hours — no jobs processed, no notification emails sent during that window. Once the new
illuminate/queueis incomposer.lock, the worker cannot run.Root Cause
Illuminate\Queue\Worker::getPausedQueues()(added in Laravel 12) was extended in a way that delegates to the queue manager:It is called unconditionally inside the worker's pop loop:
Flarum binds
\Illuminate\Contracts\Queue\FactorytoFlarum\Queue\QueueFactory, which implements only the singleconnection()method that the contract requires. The Worker's$this->manageris thatQueueFactoryinstance — it has nogetPausedQueues(), nogetRestartTimestamp(). Same root cause would surface for the$restartablepath the next time it gets hit.Steps to Reproduce
illuminate/queue ^12.xwith thegetPausedQueuesWorker change).database/syncshould reproduce the same fatal once polling fires).php flarum queue:work(or any supervisor-managed worker) — the very first pop logs the fatal and exits, supervisor restarts, repeat.Expected
Worker runs without fatals against the existing
QueueFactory. Pause/restart polling is genuinely optional in Laravel 12 — it exists forphp artisan queue:pause, which Flarum doesn't expose.Suggested Fix
Use Laravel's own opt-out,
Illuminate\Queue\QueueManager::withoutInterruptionPolling(), or equivalently flip the two static gates the Worker honours, inFlarum\Queue\Console\WorkCommand::handle():This is the upstream-blessed opt-out — see
QueueManager::withoutInterruptionPolling()atvendor/illuminate/queue/QueueManager.php:312, which does exactly:With these flags off,
Worker::getPausedQueues()and the restart-cache check return early without ever touching$this->manager, so neither method needs to exist onQueueFactory. This also covers any future Laravel additions that gate behind$pausable/$restartable, which a per-method shim onQueueFactorywouldn't.(An alternative is to shim
getPausedQueues($connection, $queues) { return []; }onQueueFactory, but that's reactive — every future Laravel release that adds another manager-method behind the same flags would need a new shim.)Environment
illuminate/queue^12 (just pulled by composer)flarum-queueworkerAdditional Context
Discovered on production via 8,000+
flarum.ERRORentries in a single day's log. Workaround applied locally by setting the two statics inFlarum\Queue\Console\WorkCommand::handle(). Confirmed worker stable past the previous 3-minute crash interval; backlog drained.