简体   繁体   English

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

[英]How to cancel queued job in Laravel or Redis

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 docs but 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?)?或者也许有工具已经使这变得容易(也许是 FastoRedis?)? In that case, instructions about how to achieve this goal that way would also be really helpful.在这种情况下,有关如何以这种方式实现此目标的说明也将非常有帮助。 Thanks!谢谢!

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

UPDATE:更新:

Look at the comprehensive answer I provided below .看看我在下面提供的综合答案

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.在此作业中,在发送电子邮件之前,检查 emailAddress-sendTime 对。 If is correct, send the email, if not, return true and the email won't send and the job will finish.如果正确,则发送电子邮件,如果不正确,则返回 true,电子邮件不会发送,作业将完成。

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

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

Delete job by id.按 id 删除作业。

$job = (new \App\Jobs\SendSms('test'))->delay(5);
$id  = app(Dispatcher::class)->dispatch($job);

$res = \Illuminate\Support\Facades\Redis::connection()->zscan('queues:test_queue:delayed', 0, ['match' => '*' . $id . '*']);
$key = array_keys($res[1])[0];

\Illuminate\Support\Facades\Redis::connection()->zrem('queues:test_queue:delayed', $key);

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) );

$connection is the Redis connection name which is null by default, and The $queue is the name of the queue / tube which is 'default' by default! $connection是 Redis 连接名称,默认为 null, $queue是队列/管的名称,默认为 'default'!

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

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 handle method 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]);
         }
      }
  }

删除所有排队的作业:

Redis::command('flushdb');

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

从队列中删除作业。

$this->delete();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM