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
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.
I ended up making a bash shell script to execute horizon:forget on each failed job, not just remove the keys from Redis. Because you want to remove it gracefully, as the key is stored in multiple places in Redis, not just in the failed_jobs set.
echo -e "SELECT 2\nZREVRANGE fintable_horizon:failed_jobs 0 -1" | redis-cli | tail -n +2 | xargs -L 1 -t php artisan horizon:forget
Note "fintable_horizon" is my prefix and "2" is my Redis database where horizon meta info is stored. Change those two variables.
The output looks like this:
php artisan horizon:forget 04124871-0afa-407f-8d06-fdf4d6110850
Failed job deleted successfully!
php artisan horizon:forget 431f67c2-e61c-4912-85b5-d068c874d6b0
Failed job deleted successfully!
...
...
Can we take another look at this? @preeteshjain's solution works.
Most helpful comment
I agree that it would be nice to have a feature to remove a single failed job - via a button "remove" e.g.