web-dev-qa-db-ja.com

LaravelまたはRedisでキューに入れられたジョブをキャンセルする方法

特定のemailAddress-sendTimeペアを持つMailableをキャンセルできるように、Redisキュー内のすべての保留中のジョブを参照するにはどうすればよいですか?

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

更新:

包括的な 以下で提供した回答 をご覧ください。

12
Ryan

新しい包括的な回答:

Dispatchable特性の代わりに、独自のカスタムDispatchableWithControl特性を使用するようになりました。

私はこのように呼んでいます:

$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遅延Mailableがキューに保存される方法のようです。

私のために働いた別のアプローチは、Windows PCに Redis Desktop Manager をインストールすることでした。

私はphpRedisAdminを好むと思います。なぜなら、ウェブから(任意のデバイスを使用して)アクセスできるからです。

3
Ryan

キューに入っているすべてのジョブを削除する:

Redis::command('flushdb');
7

簡単にします。

後のオプションでメールを送信しないでください。後のオプションでジョブをディスパッチする必要があります。このジョブはメールを送信する責任があります。

このジョブ内で、電子メールを送信する前に、emailAddress-sendTimeのペアを確認してください。正しい場合はメールを送信し、そうでない場合はtrueを返します。メールは送信されず、ジョブは終了します。

6
Sangar82

たぶんそれをキャンセルする代わりに、Redisから実際に削除することができます。IveがRedisで forgetコマンドに関する公式ドキュメント から、そして redisと対話するLaravel公式ドキュメント 基本的に、インターフェイスからRedisコマンドを呼び出します。forgetコマンドを呼び出して、実際にnode_idを渡すことができれば、この場合、イメージにある番号と思いますDEL 1517797158「キャンセル」を達成できると思います。

2
Nikola Gavric

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]);
         }
      }
  }
1
user320487

お役に立てれば

$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は、デフォルトではnullであるRedis接続名であり、$queueはキュー/チューブの名前で、デフォルトでは「デフォルト」です!

ソース: https://stackoverflow.com/a/42182586/6109499

1
melsaka