#Pausing Specific Queues During Maintenance Without Blocking Job Dispatching (Horizon)

7 messages · Page 1 of 1 (latest)

robust fjord
#

Hey folks,

I’ve run into an interesting issue and would really appreciate your input.

During our maintenance window (usually from 11 PM to 2 AM), I need to pause processing for certain queues, while still allowing the maintenance queue to continue processing as normal.

The key is that jobs should still be queued, just not processed during that time.

My question is:
Does Horizon support this kind of behavior out of the box, or is there a recommended approach to achieve this?

potent ridge
#

Maybe an possible PR and Addition to the artisan down command? 🤔

#

Do you currently even use the down command for your "maintenance window"?

robust fjord
#

Message:
The maintenance window is stored in the database and varies daily, so I can’t rely on Laravel’s php artisan down command for this use case.

I’ve tried multiple approaches—including a middleware and an event listener—to delay job processing during maintenance. The idea is to release jobs back to the queue if they fall within the active maintenance window. However, in all cases, the jobs end up being marked as failed, which is not the intended behavior.

Here’s the simplified event listener logic I used:|

<?php

declare(strict_types=1);

namespace App\Providers;

use App\Actions\Maintenance\CheckIfMaintenanceIsActive;
use Illuminate\Queue\Events\JobProcessing;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\ServiceProvider;

class QueueMaintenanceServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Queue::before(function (JobProcessing $event) {
            $this->handleMaintenanceDelay($event);
        });
    }

    private function handleMaintenanceDelay(JobProcessing $event): void
    {
        $job = $event->job;
        $payload = $job->payload();

        // Get the actual job instance
        $jobData = unserialize($payload['data']['command']);

        if (! $this->shouldProcessJob($jobData, $payload)) {
            $job->release(300);
        }
    }
}

Even though I’m calling $job->release(300), the job is still being marked as failed in Horizon. The goal is to gracefully re-queue the job for later execution once the maintenance window has ended—without flagging it as failed.

placid urchin
#

I believe calling release() counts as an attempt, and if it hits the max $tries, it'll be marked as failed.

potent ridge
#

@robust fjord
OPTION 1:
What you could do is having multiple workers with different queues setup and then killing the workers you don't want and reinitialize them after maintenance. This would be the "manual" way of doing this.

e.g. having 2 workers
1 handling all normal events default queue -> gets killed while maintenance
1 handling all maintenance events. maintenance queue -> continues running

OPTION 2:

Another thing I just saw is actually queues stopping when using php artisan down
If you pull the dynamic maintenance times from the database via an scheduled job, you could then trigger the maintenance from there.

This will result in all regular workers pausing during maintenance.

And then you have 1 worker with the php artisan queue:work --queue=maintenance --force command which continues working during Laravel maintenance.

robust fjord
#

@potent ridge, I’m also using Horizon to manage the jobs. I’ll give your suggestions (mainly option 2) a try and see if it works. Thanks so much!

I’ll get back to you as soon as I have more info or results. 🙂