質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

959閲覧

railsで一斉メールの処理が重く、実アプリでリクエストタイムアウトエラーがでてしまいます。処理を軽くする方法はないでしょうか?

akikko

総合スコア32

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2020/08/17 14:15

編集2020/08/17 14:17

前提・実現したいこと

メールマガジンのように、リスト全員にメールを送るメソッドを実装しています。
(個々人のメールアドレスが漏洩しないよう、全員一人ひとりのアドレスをto:に入れています。)

しかし、実際のアプリで35名に対し、メールを送ろうとしたら、
ブラウザが30秒実行中になってしまい、タイムアウトエラーが発生してしまいました。
処理を軽くするためにはどうすればよいでしょうか?

実アプリでして・・・大変頭を悩ませています。
どなたか教えて下さると嬉しいです。

該当のソースコード

controller.rb

@supporters = Supporter.where(event_id: params[:event_id], activation: 1, agreement: 1).pluck(:email, :name) @supporters.each do |supporter| EntryMailer.report_new_mail(@event1,@report1,supporter,url).deliver_now end

entry_mailer.rb

def report_new_mail(event,report,supporter,url) @event_title = event.title @report_title = report @supporter = supporter @url = "https://#{url}" mail(subject: "新規投稿" , to: @supporter[0], from: '"office" <info@###>') end

試したこと

ちなみになのですが・・・、entry_mailer.rbの中で、
each do || でサポーターのメールアドレス1件ずつ取り出して、toに入れようとしたのですが、
エラーになってしまい、仕方がなくコントローラーでeach do しています。

また、to: に全員のメールアドレスの記載がされたり、
bccで送信するといった方法はとりたくないと考えております。
メールマガジンのように、to:に1名1名入れて送信したいです。

教えて頂けますと本当にうれしいです。
どうぞよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2020/08/17 21:59

deliver_laterではなくdeliver_nowを使っている理由はなんですか?
akikko

2020/08/18 04:01

ご指摘ありがとうございます! 最初に習ったのが、deliver_nowでしたので、それ以来ずっとそのまま使用していました???? そもそもdeliver_laterという方法があるのですね???? これを使用した場合、仮に処理中にブラウザを閉じてしまっても処理は継続されるものなのでしょうか?
guest

回答1

0

ベストアンサー

メールを送信する処理は対象の数が多くなると非常に時間がかかります。
なので、基本的にはコントローラで完結するのは無理があります。
最も簡単な方法としては、メール内容と宛先のメールアドレスを送信予約テーブルに対象の数だけ登録しておき、cronなどでコントローラではなく、rails runnerでバッチ処理で送信する方法があります。
送信予約テーブルにはステータスを入れておき、送信完了、送信待ち、エラーなどの状態を保存しておきます。

メールアドレスは、空メールなどで確認せずに手打ちで入力させている場合、適当なメールアドレスだったり打ち間違いなどが多発しますので、必ず送信できるとは限りません。
存在しないメールアドレスに対してメールを送っていると、相手のメールサーバから自分のサーバのIPがブロックされてしまうケースもあります。
他にも、例えば同一ドメイン(@gmail.comとか@docomo.ne.jpなど)に対しては、短時間にメールを送ると相手のメールサーバからブロックされてしまうケースもあります。
とにかく届かないメールアドレスにはできるだけ送信しないようにしなければいけません。
だから例えば、1000件メールを送りたいからといって、一斉に送信するというのは無理という事です。

理想としては、ユーザ登録の時点でメールアドレスを入れさせて、専用のユーザ登録フォームURLから登録させる=メールが確実に受信できている事を担保するというステップが今時のサービスでは必須です。

手打ちでメールアドレスを入れさせて、受信確認もせずにユーザ登録完了というのは絶対避けたほうが良いです。
メールを送って相手に届ける必要があるのであればこの手間は惜しむべきではありません。

投稿2020/08/17 14:38

編集2020/08/17 14:41
mingos

総合スコア4032

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akikko

2020/08/18 04:07

ご指摘ありがとうございます!!!本当にありがたいです。 >cronなどでコントローラではなく、rails runnerでバッチ処理で送信する方法があります。 こちら、初めて知りました。まずは一度調べてみます。 ちなみに、raccy様がご指摘くださったように、deliver_laterを使用しても、いずれにしても大人数になればなるほど処理も重くなるため、rails runnerを使用することが必要ということでしょうか? メールアドレスもご丁寧にご指摘ありがとうございます。 こちらは、登録時にメールがアドレスに飛び、メール内のアドレスをクリック頂くことで本登録できる状態になっておりますので、ご指摘事項はクリアーできているかと思っております。 本当にありがとうございます????
mingos

2020/08/18 04:22

> ちなみに、raccy様がご指摘くださったように、deliver_laterを使用しても、いずれにしても大人数になればなるほど処理も重くなるため、rails runnerを使用することが必要ということでしょうか? そうですね。 人数が少なければ、deliver_laterで問題ないかもしれませんけど、大人数になったら、 限界があるのではないかなと思います。 ただ、先回りしてやりすぎると手間をかけすぎてしまうという事もありますので、 いったんはdeliver_laterで対処しておくのもいいと思います。
akikko

2020/08/18 04:55

ありがとうございます!とても助かります。 はい、まだまだスタートしたばかりのアプリですので、一旦laterで処理書きます。 継続的にrunnnerを学びまして切り替えを行って参ります! またどうぞご指南頂けますと幸いです。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問