laravel / horizon

Dashboard and code-driven configuration for Laravel queues.
https://laravel.com/docs/horizon
MIT License
3.85k stars 645 forks source link

how do you clear failed jobs? #122

Closed vesper8 closed 7 years ago

vesper8 commented 7 years ago

I know that artisan cache:clear does the trick currently but that clears everything and if you're using a different redis for cache as recommended then that won't work

but isn't there another way? I thought I could just do pa queue:flush but it seems that now that we have horizon we can't use the queue commands to list failed jobs or flush them

it would be nice if some controls were added to the web interface to perform these tasks too

themsaid commented 7 years ago

Failed jobs are cleared every 7 days automatically.

mkantautas commented 7 years ago

I agree that it would be nice to have a feature to remove a single failed job - via a button "remove" e.g.

dimsav commented 6 years ago

artisan queue:flush Flush all of the failed queue jobs

It would be nice to make this compatible with horizon. Although the command empties the mysql table, horizon is not affected.

jasperf commented 6 years ago

I am using redis for queues and artisan queue:flush works for mysql table only it seems and redis is not supported as a database.. So I am confused how I am supposed to remove queues from redis.

dimsav commented 6 years ago

@jasperf you can use the horizon dashboard, just open the "failed" tab on the left.

jasperf commented 6 years ago

@dimsav I can open that tab and see the failed jobs. I can retry them, but I cannot remove them..

screen shot 2018-07-31 at 1 44 52 pm

stefblokdijk commented 6 years ago

The easiest way for me was to run artisan queue:flush and then delete these redis keys in an Redis GUI (or CLI) like Medis.

I manually deleted the horizon:failed_jobs key. Then I deleted all the other failed jobs with this Redis CLI command. (source: stackoverflow)

EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 horizon:failed:*

I really hope there will be a simple artisan command line for this.

kharysharpe commented 6 years ago

Hope this is helpful, you can create a command and execute:

    public function handle()
    {
        Redis::connection()->del('horizon:failed:*'); 
        Redis::connection()->del('horizon:failed_jobs');
    }

Would be great if this came builtin

Vercoutere commented 5 years ago

I agree that it would be beneficial to allow the deletion of failed jobs. Sometimes a failed job doesn't need retrying after it has been handled internally, and it's preferable to remove it from the list of failed jobs for clarity.

robtesch commented 5 years ago

Extending @kharysharpe's answer a bit, the below snippet will also respect your horizon config's custom prefix (if you have one).

Redis::connection()->del([config('horizon.prefix').'failed:*']);
Redis::connection()->del([config('horizon.prefix').'failed_jobs']);

I've wrapped all this up into an artisan command "horizon:flush" which calls the queue:flush first:

    public function handle()
    {
        $this->call('queue:flush');
        Redis::connection()
             ->del([config('horizon.prefix').'failed:*']);
        $this->info('each individual failed job flushed');
        Redis::connection()
             ->del([config('horizon.prefix').'failed_jobs']);
        $this->info('failed_jobs flushed');
    }
mikeburton220 commented 5 years ago

Hope this is helpful, you can create a command and execute:

    public function handle()
    {
        Redis::connection()->del('horizon:failed:*'); 
        Redis::connection()->del('horizon:failed_jobs');
    }

Would be great if this came builtin

I used tinker to run these lines. Works!

jasperf commented 5 years ago

@mikeburton220 @kharysharpe mentioned this function earlier on. Using tinker is a quick way to use it though. Do not think it is built in yet, but it can be done this way and or added as another job. Thanks for the feedback!

ryancwalsh commented 4 years ago

I appreciated the tips from @kharysharpe and @robtesch and adapted it to:

public function handle() {
    $this->info('Calling queue:flush ...');
    $this->call('queue:flush');
    foreach ([config('horizon.prefix') . 'failed:*', config('horizon.prefix') . 'failed_jobs'] as $delCommand) {
        $this->info('In Redis, calling `del` with: ' . $delCommand);
        Redis::connection()->del([$delCommand]);//Remember to call `use Illuminate\Support\Facades\Redis;` above.
    }
    $this->info('Deleted each individual failed job from Horizon and deleted failed_jobs from Horizon.');
}

But I found myself in a weird situation (presumably unrelated to those commands) where I still saw a lot of failed jobs on the webpage at /horizon/failed and a lot of old keys in Redis, but they did not have "failed" in their key names.

It was bizarre.

I then ended up deleting all of them by running redis-cli --scan --pattern myPrefixHere_horizon:* | xargs redis-cli del (from https://rdbtools.com/blog/redis-delete-keys-matching-pattern-using-scan/).

Now finally the webpage at /horizon/failed says "There aren't any failed jobs."

fgilio commented 4 years ago

... But I found myself in a weird situation (presumably unrelated to those commands) where I still saw a lot of failed jobs on the webpage at /horizon/failed and a lot of old keys in Redis, but they did not have "failed" in their key names.

It was bizarre.

I then ended up deleting all of them by running redis-cli --scan --pattern myPrefixHere_horizon:* | xargs redis-cli del (from https://rdbtools.com/blog/redis-delete-keys-matching-pattern-using-scan/).

Now finally the webpage at /horizon/failed says "There aren't any failed jobs."

Same thing happened to me, but I cannot just delete all keys. Does anyone know if this is something to be expected?

preeteshjain commented 4 years ago

This issue is kind of frustrating. Here's what I've done to flush Redis with a simple command:

Create a new command:

php artisan make:command FlushRedis --command=flush:redis

Add this use statement to your command:

use Illuminate\Support\Facades\Redis;

Note: If you add use Redis; on the command file, it will lead to errors, because it can't be called statically.

Now in the handle() method of this command, add this line:

Redis::command('flushdb');

Register this command in App\Console\Kernel.php:

protected $commands = [
    ...
    '\App\Console\Commands\FlushRedis',
];

All done!

Now you can simply run this command in the future to clear all the jobs from Redis (and Horizon):

php artisan flush:redis

This should be the output:

image


I agree with @kharysharpe, this should be built-in.

MarGul commented 4 years ago

Hope this is helpful, you can create a command and execute:

    public function handle()
    {
        Redis::connection()->del('horizon:failed:*'); 
        Redis::connection()->del('horizon:failed_jobs');
    }

Would be great if this came builtin

I used tinker to run these lines. Works!

Don't forget to use the full namespace like \Illuminate\Support\Facades\Redis::connection()->del('...'); or import it if using tinker.

alielmajdaoui commented 3 years ago

This is now supported in Horizon 5.

Simply, grab the job id from the failed_jobs table and execute this artisan command:

php artisan horizon:forget JOB_ID

It will delete it from MySQL/Postgresfailed_jobs table, as well as Redis PREFIX_horizon:failed_jobs zset.

Docs: https://laravel.com/docs/8.x/horizon#deleting-failed-jobs

marianvlad commented 2 years ago

Based on Horizon source code, I set the trim config to 1 minute instead 7 days and run the code like here

use Laravel\Horizon\Contracts\JobRepository;

config(['horizon.trim.failed' => 1]);

$jobRepository = resolve(JobRepository::class);
$jobRepository->trimFailedJobs();
martio commented 2 years ago

For Laravel 9 and PHP 8.1

<?php
namespace App\Console\Commands\Horizon;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

/**
 * Console.
 */
class ClearMetricsCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:horizon:clear-metrics';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Flush the Horizon metrics';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle(): int
    {
        Redis::connection(name: 'horizon')->client()->flushAll();

        $this->info(string: 'The command was successful!');

        return 0;
    }
}
jimtaylor123 commented 1 year ago

This is what I use in my job to clear just the failed jobs on Laravel 10:

    Redis::connection()->zremrangebyscore(
        'failed_jobs', CarbonImmutable::now()->subMinutes(config('horizon.trim.failed', 10080))->getTimestamp() * -1, '+inf'
     );
Luke-SF commented 10 months ago
php artisan horizon:forget JOB_ID

Too bad there isn't a clear "all" or "*" command in Horizon?

yipeecaiey commented 4 months ago

stumbled across this old thread...looks like that option IS now available php artisan horizon:forget --all