2016-03-21 3 views
7

Я использую обратный вызов after_action в своих почтовых программах для записи этого письма. Письма отправляются через Delayed Job. Это работает, за исключением случаев, когда мы не можем связаться с удаленным сервером - в этом случае письмо не отправляется, но мы записываем, что это было. Задержка задания повторно отправляет электронное письмо позже, и оно успешно доставлено, но затем мы записали, что были отправлены два письма.Обнаружение сбоев доставки почтовых сообщений в обратных вызовах after_action

Это выглядит примерно так:

class UserMailer < ActionMailer::Base 

    after_action :record_email 

    def record_email 
    Rails.logger.info("XYZZY: Recording Email") 
    @user.emails.create! 
    end 

    def spam!(user) 
    @user = user 
    Rails.logger.info("XYZZY: Sending spam!") 
    m = mail(to: user.email, subject: 'SPAM!') 
    Rails.logger.info("XYZZY: mail method finished") 
    m 
    end 
end 

Я называю этот код, как это (с помощью delayed job performable mailer):

UserMailer.delay.spam!(User.find(1)) 

Когда я пошагово это отладчик, кажется, что мой метод after_action называется до того, как почта доставлена.

[Job:104580969] XYZZY: Sending spam! 
[Job:104580969] XYZZY: mail method finished 
[Job:104580969] XYZZY: Recording Email 
Job UserMailer.app_registration_welcome (id=104580969) FAILED (3 prior attempts) with Errno::ECONNREFUSED: Connection refused - connect(2) for "localhost" port 1025 

Как я могу поймать сетевые ошибки в моем методы почтовой программы и запись о том, что попытка электронной почты не удалась или вообще ничего не делала? Я использую Rails 4.2.4.

ответ

2

Это то, что я придумал, я хотел бы иметь лучший путь.

Я использовал функцию обратного вызова доставки почты:

delivery_callback.rb

class DeliveryCallback 
    def delivered_email(mail) 
    data = mail.instance_variable_get(:@_callback_data) 
    unless data.nil? 
     data[:user].email.create! 
    end 
    end 
end 

конфигурации/инициализирует/mail.rb

Mail.register_observer(DeliveryCallback.new) 

И я заменил свой метод record_email:

class UserMailer < ActionMailer::Base 

    after_action :record_email 

    def record_email 
    @_message.instance_variable_set(:@_callback_data, {:user => user}) 
    end 
end 

Это, похоже, работает, если удаленный сервер недоступен, обратный вызов deliver_email не вызывается.

Есть ли лучший способ!?!?

-1

Попробуйте следующее:

class UserMailer < ActionMailer::Base 

    # after_action :record_email 

    def record_email 
    Rails.logger.info("XYZZY: Recording Email") 
    @user.emails.create! 
    end 

    def spam!(user) 
    begin 
     @user = user 
     Rails.logger.info("XYZZY: Sending spam!") 
     m = mail(to: user.email, subject: 'SPAM!') 
     Rails.logger.info("XYZZY: mail method finished") 
     m 
    rescue Errno::ECONNREFUSED 
     record_email 
    end 
    end 
end 
+0

Это не работает. Он немного отличается от того, как отложенная работа обрабатывает электронную почту. Он вызывает ваш метод почтовой программы, а затем вызывает доставку (или доставляет его). Таким образом, фактическая доставка осуществляется за пределами спама! метод –

+0

Я также хочу, чтобы что-то работало, не задумываясь о его реализации на каждом методе почтовой рассылки или в chagne все мои существующие методы почтовой программы (их около 30) –

0

Сообщение отладки вы показали прекрасный смысл - действие почтовой программы заканчивается немедленно, потому что почтовое действие сам по себе асинхронному, обрабатываются отложенной работой в совершенно другом процессе. Таким образом, сам класс почтовой программы не знает, как закончилось рассылку.

Вместо этого я хочу, чтобы вы использовали Delayed job hooks. Вам придется переписывать свои почтовые программы и звонки, чтобы отправить электронные письма немного.

Я не проверял его полностью, но что-то по следующим направлениям должно работать:

class MailerJob 

    def initialize(mailer_class, mailer_action, recipient, *params) 
    @mailer_class = mailer_class 
    @mailer_action = mailer_action 
    @recipient = recipient 
    @params = params 
    end 

    def perform 
    @mailer_class.send(@mailer_action, @recipient, *@params) 
    end 

    def success(job) 
    Rails.logger.debug "recording email!" 
    @recipient.emails.create! 
    end 

    def failure(job) 
    Rails.logger.debug "sending email to #{@recipient.email} failed!" 
    end 

end 

MailerJob является custom job для запуска с помощью отложенной работы.Я попытался сделать это как можно более общим, поэтому он принимает класс почтовой программы, действие почтовой программы, получателя (как правило, пользователя) и другие необязательные параметры. Также требуется, чтобы recipient имел ассоциацию emails.

У задания есть два крючка: success при успешном выполнении почтового действия, которое создает запись email в базе данных, а другую - для сбоя регистрации. Фактическая отправка выполняется в методе perform. Обратите внимание, что внутри него метод delayed не используется, так как все задание уже выделено в фоновом режиме. Задержка очереди заданий при вызове.

Чтобы отправить почту с помощью этого пользовательского задания вы должны Ставить его задержанной работы и т.д .:

Delayed::Job.enqueue MailerJob.new(UserMailer, :spam!, User.find(1)) 
+0

Мой коллега предложил это. Я думаю, что это довольно хорошая идея, но я бы расширил функциональность Delayed :: PerformableMailer (https://github.com/collectiveidea/delayed_job/blob/v4.1.1/lib/delayed/performable_mailer.rb). Я думаю, что вы ошибаетесь в том, что действие рассылки является асинхронным. Вы правы, когда я вызываю UserMailer.delay.spam! метод почты происходит позже, но фактическая работа по отправке электронной почты является синхронной в течение отложенной работы. –

+0

Я имел в виду «асинхронный» в том смысле, что действие почтовой программы не дожидалось результата фактической рассылки (сделанное отложенным заданием). И мне очень жаль, но я не совсем понимаю, в чем проблема с подходом крючков? Из [source] (https://github.com/collectiveidea/delayed_job/blob/2014009496dd0b2af217ab322f74f91fe4e26097/lib/delayed/message_sending.rb#L2) кажется, что внутренне PerformableMailer - это не что иное, как класс, который довольно часто задает почтовые рассылки так же, как мой ответ выше. – BoraMa

+1

Почему downvote? – BoraMa

 Смежные вопросы

  • Нет связанных вопросов^_^