はじめに
以前、とあるシステムの開発でメール一括送信機能を開発する機会がありました。開発終了後本番環境でメール一括送信機能を使ってメール送信されたのですが、なぜが同じ人に対して大量にメール送信されたり、ある人に対してはメール送信されていなかったりしました...今後同じような事態が発生しないように、何が問題だったのか、どう解決したのかまとめていこうと思います。
問題点
メール一括送信機能はrailsのdelayed_jobを用いて実装していました。具体的には、「メール一括送信job」の中で全ての対象者全員に対してメール送信する処理を実装していました。
メール一括送信機能を実行すると、実装したdelayed_jobが実行され、一人目二人目とユーザに対してメール送信されるのですが、何らかの理由でn人目のユーザに対してメール送信失敗し、再度delayed_jobがリトライし、また一人目二人目からメール送信が始まりn人目でメール送信失敗し、再度delayed_jobがリトライされるの繰返しが発生していました。
dalayed_jobに関して調査してみると、delayed_jobの設定ファイルに失敗した時のリトライ数を記載しない場合、デフォルトで25回リトライされる設定になることが分かりました。
すぐさま設定ファイルを確認すると、リトライ数は記載しておらず、デフォルトの25回リトライされる設定になっていたことが原因で、同じ人に対して大量にメール送信されていました。
また、メール送信失敗した時の処理を考慮せずに、「メール一括送信job」の中で全ての対象者全員に対してメール送信する処理を実装していたことが原因で、上記で記載したようにメール送信に失敗した場合は、最初のユーザへのメール送信に戻るため失敗したユーザ以降のユーザにメール送信できなくなっていました。
解決策1
delayed_jobの設定ファイルに失敗した時はリトライさせないように下記の設定を記載することで、メール送信失敗時に同じ人に対して大量にメールされる事象を解決しました。
Delayed::Worker.max_attempts = 0
しかし、この解決策1のみだと、n人目のユーザにメール送信失敗した場合、n+1人目以降のユーザにメール送信できない事象は解決できません。
解決策2
そのため、メール一括送信機能のdelayed_jobの構造を「メール一括送信job」のみの構造から、「メール送信job」と「対象者分のメール送信jobを作成するjob」の二つを用いる構造に変更しました。その結果、メール送信に失敗したユーザがいた場合でも、jobの構造上対象者全員にメール送信されるため、失敗したユーザ以降のユーザにメール送信できない事象は発生しないようになりました。
おわりに
不具合が生じた際に影響が大きい機能に関しては特に失敗した時の動きを想定して処理を作りこむことが大切だと身をもって感じました。今後同じような過ちを繰り返さないようにdelayed_jobの設定や構造は気を付けていきます。
参考