如何取消 Laravel 或 Redis 中的排队作业

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48255735/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 17:14:46  来源:igfitidea点击:

How to cancel queued job in Laravel or Redis

laravelredisqueuedelayjobs

提问by Ryan

How can I browse all the pending jobs within my Redis queue so that I could cancel the Mailable that has a certain emailAddress-sendTime pair?

如何浏览 Redis 队列中的所有待处理作业,以便取消具有特定 emailAddress-sendTime 对的 Mailable?

I'm using Laravel 5.5 and have a Mailable that I'm using successfully as follows:

我正在使用 Laravel 5.5 并有一个我成功使用的 Mailable 如下:

$sendTime = Carbon::now()->addHours(3);
Mail::to($emailAddress)
      ->bcc([config('mail.supportTeam.address'), config('mail.main.address')])
                    ->later($sendTime, new MyCustomMailable($subject, $dataForMailView));

When this code runs, a job gets added to my Redis queue.

当这段代码运行时,一个作业被添加到我的 Redis 队列中。

I've already read the Laravel docsbut remain confused.

我已经阅读了Laravel 文档,但仍然感到困惑。

How can I cancel a Mailable (prevent it from sending)?

如何取消 Mailable(防止其发送)?

I'd love to code a webpage within my Laravel app that makes this easy for me.

我很想在我的 Laravel 应用程序中编写一个网页,这对我来说很容易。

Or maybe there are tools that already make this easy (maybe FastoRedis?)? In that case, instructions about how to achieve this goal that way would also be really helpful. Thanks!

或者也许有工具已经使这变得容易(也许是 FastoRedis?)?在这种情况下,有关如何以这种方式实现此目标的说明也将非常有帮助。谢谢!

Update:

更新:

I've tried browsing the Redis queue using FastoRedis, but I can't figure out how to delete a Mailable, such as the red arrow points to here: enter image description here

我已经尝试使用 FastoRedis 浏览 Redis 队列,但我无法弄清楚如何删除 Mailable,例如红色箭头指向此处: 在此处输入图片说明

UPDATE:

更新:

Look at the comprehensive answer I provided below.

看看我在下面提供的综合答案

采纳答案by Ryan

New, Comprehensive Answer:

新的综合答案:

I now use my own custom DispatchableWithControl trait instead of the Dispatchable trait.

我现在使用我自己的自定义 DispatchableWithControl 特征而不是 Dispatchable 特征。

I call it like this:

我这样称呼它:

$executeAt = Carbon::now()->addDays(7)->addHours(2)->addMinutes(17);
SomeJobThatWillSendAnEmailOrDoWhatever::dispatch($contactId, $executeAt);


namespace App\Jobs;

use App\Models\Tag;
use Carbon\Carbon;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Log;

class SomeJobThatWillSendAnEmailOrDoWhatever implements ShouldQueue {

    use DispatchableWithControl,
        InteractsWithQueue,
        Queueable,
        SerializesModels;

    protected $contactId;
    protected $executeAt;

    /**
     * 
     * @param string $contactId
     * @param Carbon $executeAt
     * @return void
     */
    public function __construct($contactId, $executeAt) {
        $this->contactId = $contactId;
        $this->executeAt = $executeAt;
    }

    /**
     * Execute the job. 
     *
     * @return void
     */
    public function handle() {
        if ($this->checkWhetherShouldExecute($this->contactId, $this->executeAt)) {
            //do stuff here
        }
    }

    /**
     * The job failed to process. 
     *
     * @param  Exception  $exception
     * @return void
     */
    public function failed(Exception $exception) {
        // Send user notification of failure, etc...
        Log::error(static::class . ' failed: ' . $exception);
    }

}


namespace App\Jobs;

use App\Models\Automation;
use Carbon\Carbon;
use Illuminate\Foundation\Bus\PendingDispatch;
use Log;

trait DispatchableWithControl {

    use \Illuminate\Foundation\Bus\Dispatchable {//https://stackoverflow.com/questions/40299080/is-there-a-way-to-extend-trait-in-php
        \Illuminate\Foundation\Bus\Dispatchable::dispatch as parentDispatch;
    }

    /**
     * Dispatch the job with the given arguments.
     *
     * @return \Illuminate\Foundation\Bus\PendingDispatch
     */
    public static function dispatch() {
        $args = func_get_args();
        if (count($args) < 2) {
            $args[] = Carbon::now(TT::UTC); //if $executeAt wasn't provided, use 'now' (no delay)
        }
        list($contactId, $executeAt) = $args;
        $newAutomationArray = [
            'contact_id' => $contactId,
            'job_class_name' => static::class,
            'execute_at' => $executeAt->format(TT::MYSQL_DATETIME_FORMAT)
        ];
        Log::debug(json_encode($newAutomationArray));
        Automation::create($newAutomationArray);
        $pendingDispatch = new PendingDispatch(new static(...$args));
        return $pendingDispatch->delay($executeAt);
    }

    /**
     * @param int $contactId
     * @param Carbon $executeAt
     * @return boolean
     */
    public function checkWhetherShouldExecute($contactId, $executeAt) {
        $conditionsToMatch = [
            'contact_id' => $contactId,
            'job_class_name' => static::class,
            'execute_at' => $executeAt->format(TT::MYSQL_DATETIME_FORMAT)
        ];
        Log::debug('checkWhetherShouldExecute ' . json_encode($conditionsToMatch));
        $automation = Automation::where($conditionsToMatch)->first();
        if ($automation) {
            $automation->delete();
            Log::debug('checkWhetherShouldExecute = true, so soft-deleted record.');
            return true;
        } else {
            return false;
        }
    }

}

So, now I can look in my 'automations' table to see pending jobs, and I can delete (or soft-delete) any of those records if I want to prevent the job from executing.

所以,现在我可以查看我的“自动化”表以查看待处理的作业,如果我想阻止作业执行,我可以删除(或软删除)任何这些记录。



Old Answer:

旧答案:

I set up a new app on my server and installed (on its own subdomain) this web interface for managing my Redis: https://github.com/ErikDubbelboer/phpRedisAdmin

我在我的服务器上设置了一个新应用程序并安装(在它自己的子域上)这个用于管理我的 Redis 的网络界面:https: //github.com/ErikDubbelboer/phpRedisAdmin

It allows me to edit or delete ZSet keys and values, which seems to be how Laravel delayed Mailables get saved to the queue.

它允许我编辑或删除 ZSet 键和值,这似乎是 Laravel 延迟 Mailables 保存到队列的方式。

Another approach that worked for me was to install Redis Desktop Manageron my Windows PC.

另一种对我有用的方法是在我的 Windows PC 上安装Redis 桌面管理器

I think I'll prefer phpRedisAdmin since I'll be able to access it from the web (using any device).

我想我会更喜欢 phpRedisAdmin,因为我可以从网络访问它(使用任何设备)。

回答by Sangar82

Make it easier.

让它更容易。

Don't send an email with the later option. You must dispatch a Job with the later option, and this job will be responsible to send the email.

不要发送带有稍后选项的电子邮件。您必须使用稍后的选项发送 Job,并且该 Job 将负责发送电子邮件。

Inside this job, before send the email, check the emailAddress-sendTime pair. If is correct, send the email, if not, return true and the email won't send and the job will finish.

在此作业中,在发送电子邮件之前,检查 emailAddress-sendTime 对。如果正确,则发送电子邮件,如果不正确,则返回 true,电子邮件不会发送,作业将完成。

回答by Alexandre Thebaldi

Removing all queued jobs:

删除所有排队的作业:

Redis::command('flushdb');

回答by Nikola Gavric

Maybe instead of canceling it you can actually remove it from the Redis, from what Ive read from official docs about forget commandon Redis and from Laravel official doc interacting with redisyou can basically call any Rediscommand from the interface, if you could call the forgetcommand and actually pass node_idwhich in this case I think it's that number you have in your image DEL 1517797158I think you could achieve the "cancel".

也许不是取消它,你实际上可以从 Redis 中删除它,从我从官方文档中读到的关于 Redis 上的忘记命令Laravel 官方文档与 redis 交互你基本上可以Redis从接口调用任何命令,如果你可以调用forget命令并实际通过node_id,在这种情况下,我认为这是您图像中的那个数字,DEL 1517797158我认为您可以实现“取消”。

回答by Nikola Gavric

One approach may be to have your job check to see if you've set a specific address/time to be canceled (deleted from queue). Setup a database table or cache a value forever with the address/time in an array. Then in your job's handlemethod check if anything has been marked for removal and compare it to the mailable's address/time it is processing:

一种方法可能是让您的工作检查您是否已设置要取消的特定地址/时间(从队列中删除)。使用数组中的地址/时间设置数据库表或永久缓存值。然后在你的工作handle方法中检查是否有任何内容被标记为删除,并将其与可邮寄的地址/时间进行比较:

public function handle()
{
     if (Cache::has('items_to_remove')) {
         $items = Cache::get('items_to_remove');
         $removed = null;
         foreach ($items as $item) {
             if ($this->mail->to === $item['to'] && $this->mail->sendTime === $item['sendTime']) {
                  $removed = $item;
                  $this->delete();
                  break;
             }
         }
         if (!is_null($removed)) {
             $diff = array_diff($items, $removed);
             Cache::set(['items_to_remove' => $diff]);
         }
      }
  }

回答by melsaka

hope this helps

希望这可以帮助

$connection = null;
$default = 'default';

//For the delayed jobs
var_dump( \Queue::getRedis()->connection($connection)->zrange('queues:'.$default.':delayed' ,0, -1) );

//For the reserved jobs
var_dump( \Queue::getRedis()->connection($connection)->zrange('queues:'.$default.':reserved' ,0, -1) );

$connectionis the Redis connection name which is null by default, and The $queueis the name of the queue / tube which is 'default' by default!

$connection是 Redis 连接名称,默认为空,$queue是队列/管的名称,默认为“默认”!

source : https://stackoverflow.com/a/42182586/6109499

来源:https: //stackoverflow.com/a/42182586/6109499

回答by Guy

Using redis-cli I ran this command:

使用 redis-cli 我运行了这个命令:

KEYS *queue*

on the Redis instance holding queued jobs, then deleted whatever keys showed up in the response

在持有排队作业的 Redis 实例上,然后删除响应中出现的任何键

DEL queues:default queues:default:reserved