Closed vesper8 closed 7 years ago
Failed jobs are cleared every 7 days automatically.
I agree that it would be nice to have a feature to remove a single failed job - via a button "remove" e.g.
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.
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.
@jasperf you can use the horizon dashboard, just open the "failed" tab on the left.
@dimsav I can open that tab and see the failed jobs. I can retry them, but I cannot remove them..
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.
horizon:failed_jobs
will remove the list of failed jobshorizon:failed:JOBNAME
every failed job has a key like this 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.
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 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.
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');
}
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!
@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!
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."
... 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?
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',
];
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:
I agree with @kharysharpe, this should be built-in.
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.
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
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();
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;
}
}
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'
);
php artisan horizon:forget JOB_ID
Too bad there isn't a clear "all" or "*" command in Horizon?
stumbled across this old thread...looks like that option IS now available
php artisan horizon:forget --all
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