こんにちは!Webエンジニアとして働き始めてそろそろ1年目になります。
最近、参画している案件で、特定の時間にメール・通知を送信する方法 について調べる機会がありました。
今回は、その経験で得た知見や「こうすれば良かったかも」という点を、自分自身の備忘録として、そして同じようにLaravelを学んでいる方々の参考になればと思い、まとめてみることにしました。
基本的なキューやワーカーの話も少し含みますが、今回はメールや通知の遅延実行に焦点を当てて書いていきます。
なぜメール送信にキューを使うのか?(おさらいと深掘り)
まず、なぜメール送信のような処理にキューを使うのが良いのか、簡単におさらいさせてください。
- メール送信処理(特に外部のSMTPサーバーとの通信)は時間がかかることがあります。これをユーザーのリクエスト中に同期的に行うと、ユーザーを待たせてしまいます。キューを使えば、送信処理をバックグラウンドに回せるので、ユーザーはすぐにレスポンスを受け取れます
- 短時間に大量のメール送信リクエストが発生した場合でも、キューが緩衝材となり、一度にサーバーへ高い負荷がかかるのを防げます。また、並列で処理を行うためより高速に処理を行うことが可能です。
- ネットワークの問題やメールサーバーの一時的な不調で送信に失敗しても、キューなら自動で再試行(リトライ)してくれます。これにより、メールの送信漏れリスクを減らせます
特定の時間にメールを送りたい! 遅延実行 (Delay) の使い方
毎日決まった時間にメールや通知を送信したいという要件がありました。
この時に実現できるパターンとしては下記の2種類が考えられるかと思います。
- Cronを用いたバッチ処理で行う
- キューワーカーにて遅延実行をすることで実現する
今回は、2つ目の方法に焦点を当てて行きたいと思いますl。
※おそらく本来の使い方ではない気がするので、その時間にバッチ処理を行うと負荷が気になるなどの事情がなければバッチ処理にて行う方がいいのではないか?とも思います。詳しい方がいらっしゃいましたら、是非コメントで教えてください!
ジョブをディスパッチする際に delay() メソッドを使います。
use Carbon\Carbon; // 日時操作に便利なCarbonライブラリ
// --- 例1: 10分後にジョブを実行 ---
SendSpecificEmail::dispatch($user, $data)
->delay(now()->addMinutes(10));
// --- 例2: ユーザー登録から3日後に実行 ---
$registrationDate = $user->created_at; // ユーザー登録日時
SendSpecificEmail::dispatch($user, $data)
->delay($registrationDate->addDays(3));
// --- 例3: 特定の日時(2025年4月15日 午前9時)に実行 ---
SendSpecificEmail::dispatch($user, $data)
->delay(Carbon::parse('2025-04-15 09:00:00'));
// もちろんキュー指定と組み合わせることも可能
SendSpecificEmail::dispatch($user, $data)
->onQueue('scheduled_emails') // 別のキューにするなど
->delay(now()->addHours(1)); // 1時間後
delay() に DateTimeInterface インスタンス(Carbon インスタンスや now() ヘルパの結果)を渡すことで、指定した日時までジョブの実行を遅らせることができます。
delay() を使うと、database ドライバの場合、jobs テーブルの available_at カラムに未来の日時が設定されます。キューワーカーは、この available_at が現在時刻を過ぎているジョブだけを取得して実行する仕組みになっています。
ワーカーが動いている必要: 当然ですが、指定した日時になってもキューワーカーが起動していなければジョブは実行されません。Supervisorなどでワーカーが常に稼働していることが前提です。
正確な時間ではない可能性: delay() は「少なくとも指定した時間までは実行しない」という意味合いです。ワーカーが他のジョブを処理中だったり、起動タイミングによっては、指定時刻ぴったりではなく、少し遅れて実行される可能性があります。ミリ秒単位の厳密な実行時間制御には向きません。
それぞれのメリット・デメリット
メール送信処理を行うジョブクラスを作成し、そのジョブをキューに追加する際に delay() メソッドを使って送信時間を指定する場
メリット:
実装が容易: 単純なメール送信であれば、比較的簡単に実装できます。
柔軟な送信時間設定: 個々のメールに対して異なる送信時間を設定できます。
少量のメールに適している: 数件程度のメールを個別に異なる時間に送信したい場合に便利です。
デメリット:
大量のメールには不向き: 大量のメールを異なる時間に送信する場合、キューに大量のジョブが登録され、管理が煩雑になる可能性があります。
リソース消費: 個々のメール送信が独立したジョブとしてキューに追加されるため、システムリソースを個別に消費します。
送信時間のずれ: キューワーカーの処理状況によっては、指定した時間から若干の遅延が発生する可能性があります。
スケジューリングの複雑化: 多数のメールに対してそれぞれ異なる送信時間を設定する場合、スケジューリングの管理が難しくなります。
まとめ
今回はキューワーカーを用いて遅延処理をする方法について紹介してみました。
バッチ処理で実装するだけでなく、Delayの方法でも実装を行うことができるため、メリット・デメリットを考慮した上で実装してみてください