Horizon: Add Retry All button

Created on 7 Oct 2017  路  8Comments  路  Source: laravel/horizon

It would be nice to have Retry All button

Feature request

enhancement

Most helpful comment

It would be nice to have Retry All button

Feature request

Yes, would be a nice addition.
In the past, I just opened my Chrome dev tools console and executed $('table i.icon').click();. Good enough for me.

All 8 comments

This may relate to #310

Atm, a new job is created after failed retry. Ideally, after a failed retry, the original job should be deleted and a new job is created to prevent having duplicated jobs.

e.g. Job#1 failed, Job#2 (duplicate of job#1) is created, then retry Job#2 which fails again, Job#3 (duplicate of job#2) is created. Now I have Job#1, Job#2 and Job3# do the same thing. If "Retry All" would work, I would execute 3 jobs. The end goal is to have Job#3 exists, and Job#1 and Job#2 are removed

It would be nice to have Retry All button

Feature request

Yes, would be a nice addition.
In the past, I just opened my Chrome dev tools console and executed $('table i.icon').click();. Good enough for me.

I made a little endpoint which seems to do the trick:

Route::get('/retry-all', function () {
    /** @var JobRepository $jobs */
    $jobs = app(JobRepository::class);
    return $jobs->getFailed()->map(function ($job) {
        $id = $job->id;
        dispatch(new RetryFailedJob($id));
        return $id;
    });
});

Hey all, we're gonna close this as Taylor has rejected this in the past. I don't think we'll re-consider this as we don't feel this is useful in a production environment. Sorry.

@driesvints What would you advice alternatively in a production environment?

The queue retry all command doesn't seem to use a cursor either so ends up getting killed if you have many jobs. It will also be great to be able to retry all the jobs on a particular connection.

For anyone interested, I created a model scaffold for FailedJobs table and ended up using something like this:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\FailedJob;
use Carbon\Carbon;

class FailedJobsCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'jobs:failed {connection?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Retry failed jobs';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        \ini_set('memory_limit', -1);
        \set_time_limit(0);
        $this->retryJobs();
    }

    public function retryJobs()
    {
        $total = 0;
        $connection = $this->argument('connection') ?: null;

        pcntl_async_signals(true);

        pcntl_signal(SIGINT, function () use ($total) {
            $this->info("$total jobs queued");
            return;
        });
        pcntl_signal(SIGTERM, function () use ($total) {
            $this->info("$total jobs queued");
            return;
        });

        $time = null;

        if (config('horizon.trim.failed')) {
            $time = Carbon::now()->subMinutes(config('horizon.trim.failed'));
            $this->info("Using failed after time: $time");
        }

        if ($connection) {
            if ($time) {
                $cursor = FailedJob::where('failed_at', '>=', (string)$time)->where('connection', $connection)->cursor();
            } else {
                $cursor = FailedJob::where('connection', $connection)->cursor();
            }
        } else {
            if ($time) {
                $cursor = FailedJob::where('failed_at', '>=', (string)$time)->cursor();
            } else {
                $cursor = FailedJob::cursor();
            }
        }

        foreach ($cursor as $j) {
            $total += 1;
            $payload = json_decode($j->payload, true);

            if (isset($payload['attempts'])) {
                $payload['attempts'] = 0;
            }

            $j->payload = json_encode($payload);

            $this->laravel['queue']->connection($j->connection)->pushRaw(
                $j->payload, $j->queue
            );
            $this->info("Job {$j->id} successfully queued for retry");
        }
        $this->info("$total jobs successfully queued for retry");
    }
}

@xwiz best to create something yourself like the above.

I'm just saying that the defaults currently available are not good/efficient for production use. But again I understand failed jobs can be dirty to test.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pmartelletti picture pmartelletti  路  4Comments

mikeminckler picture mikeminckler  路  3Comments

RicardoRamirezR picture RicardoRamirezR  路  3Comments

okaufmann picture okaufmann  路  3Comments

francislavoie picture francislavoie  路  5Comments