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

时间:2018-01-15 01:00:13

标签: laravel redis queue delay jobs

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

我正在使用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));

当此代码运行时,作业将添加到我的Redis队列中。

我已经阅读了Laravel docs,但仍感到困惑。

如何取消Mailable(阻止发送)?

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

或许有些工具已经让这很容易(也许是FastoRedis?)?在这种情况下,关于如何以这种方式实现这一目标的说明也将非常有用。谢谢!

更新

我尝试使用FastoRedis浏览Redis队列,但我无法弄清楚如何删除Mailable,例如红色箭头指向此处: enter image description here

UPDATE:

查看全面的answer I provided below

9 个答案:

答案 0 :(得分:8)

删除所有排队的作业:

Redis::command('flushdb');

答案 1 :(得分:5)

让它变得更容易。

请勿使用后面的选项发送电子邮件。您必须使用后面的选项发送作业,此作业将负责发送电子邮件。

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

答案 2 :(得分:2)

新的,全面的答案:

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

我称之为:

$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;
        }
    }

}

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

旧答案:

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

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

另一种对我有用的方法是在我的Windows PC上安装Redis Desktop Manager

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

答案 3 :(得分:2)

也许不是取消它,你实际上可以从Redis中删除它,从我从Redis上的official docs about forget command读取的内容,以及从Laravel official doc interacting with redis你基本上可以从界面调用任何Redis命令,如果你可以调用forget命令并实际通过node_id,在这种情况下,我认为你的图像中有这个数字DEL 1517797158我认为你可以实现& #34;取消&#34;

答案 4 :(得分:1)

希望这会有所帮助

$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是Redis连接名称,默认为null,$queue是队列/管道的名称,默认为“默认”!

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

答案 5 :(得分:1)

一种方法可能是让您的工作检查您是否已设置要取消的特定地址/时间(从队列中删除)。使用数组中的地址/时间设置数据库表或永久缓存值。然后在您的工作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]);
         }
      }
  }

答案 6 :(得分:0)

使用redis-cli运行以下命令:

KEYS *queue*

在拥有排队作业的Redis实例上, 然后删除响应中显示的所有键

DEL queues:default queues:default:reserved

答案 7 :(得分:0)

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

答案 8 :(得分:-2)

从队列中删除作业。

$this->delete();