6

私は ActionMailer deliver_later w ActiveJobs / Sidekiq を使用しています:

config.active_job.queue_adapter = :sidekiq

MailCatcher を使用して開発モードでテストしているため、キャッチできる唯一のエラーは Errno::ECONNREFUSED で、1025 ではなくポート 1026 を設定しています。

delivery_now をテストすると、Errno::ECONNREFUSED エラーが発生しましたが、問題ありません。

begin
   MessageMailer.contact_me_email(@message).deliver_now
   rescue Errno::ECONNREFUSED, Net::SMTPAuthenticationError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError => e
     flash[:error] = "Problems sending mail. Please try again later"
     # delete message or resend it ?
     byebug
     @message.destroy
     format.html { render :new }
   end

しかし、deliver_later をリクエストすると、リクエストが sidekiq メーラーのキューに溜まり、エラーがキャプチャされません...

       begin
   MessageMailer.contact_me_email(@message).deliver_later(wait: 1.minute ) # in mailers queue
   rescue Errno::ECONNREFUSED, Net::SMTPAuthenticationError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError => e
     flash[:error] = "Problems sending mail. Please try again later"
     # delete message or resend it ?
     byebug
     @message.destroy
     format.html { render :new }
   end

この場合、SMTP エラーをどのようにキャプチャしてレスキューできますか? それを処理するのはSidekiqの責任だと思います...どんなヒントでも歓迎..

4

1 に答える 1

14

ActiveJobs を使用すると、rescue_fromメソッドを使用してジョブを実行したときに発生するエラーをレスキューできます。APIを参照してください。ActiveJob サブクラスでこのメソッドを実装する必要があります。

ActionMailer は DeliveryJobs を使用してメッセージをジョブとして配信するため、例外を処理するためにこのクラスに rescue_from メソッドを追加する必要があります。

たとえば、次のように配置できますconfig/initializers/action_mailer.rb

ActionMailer::DeliveryJob.rescue_from(StandardError) do |exception|
    Rails.logger.error "Original record not found: #{@serialized_arguments.join(', ')}"
end

これにより、すべての StandardError がクリーンにレスキューされ、例外が発生する代わりに単純にログに記録されます。ロールバーを静かにするためにこれを自分で実装しました。

これはまれなケースであるため、同様にテストすることをお勧めします。

spec/initializers/action_mailer_spec.rb:

RSpec.describe 'ActionMailer::DeliveryJob error recovery' do

   it 'should log the deserialization errors' do
     @user = create(:user)
     MyCustomMailer.send_something(@user).deliver_later
     @user.destroy

     expect(Rails.logger).to receive(:error).at_least(:once)
     Delayed::Worker.new.work_off
   end

end
于 2016-01-22T18:59:38.613 に答える