2016-03-21 25 views
7

Tôi đang sử dụng cuộc gọi lại after_action trong thư của tôi để ghi lại email đã được gửi. Các email được gửi qua công việc bị trì hoãn. Thao tác này hoạt động, trừ khi chúng tôi không thể kết nối với máy chủ từ xa - trong trường hợp đó, email không được gửi, nhưng chúng tôi ghi lại nó. Công việc bị trì hoãn thử lại email sau đó và nó được gửi thành công, nhưng sau đó chúng tôi đã ghi lại rằng hai email đã được gửi.Phát hiện lỗi gửi thư của người gửi hành động trong các cuộc gọi lại sau cuộc gọi

Nó trông giống như sau:

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 

tôi gọi mã này như thế này (sử dụng delayed job performable mailer):

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

Khi tôi bước qua này trong một trình gỡ lỗi, có vẻ như phương pháp after_action tôi được gọi là trước khi thư được gửi.

[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 

Làm cách nào tôi có thể gặp lỗi mạng trong phương pháp gửi thư và ghi lại rằng các nỗ lực email không thành công, hoặc không làm gì cả? Tôi đang sử dụng Rails 4.2.4.

Trả lời

2

Đây là những gì tôi đã đưa ra, tôi rất thích có một cách tốt hơn.

tôi đã sử dụng callback giao Mail:

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 

config/khởi/mail.rb

Mail.register_observer(DeliveryCallback.new) 

Và tôi đã thay thế phương pháp record_email của tôi:

class UserMailer < ActionMailer::Base 

    after_action :record_email 

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

Điều này có vẻ hoạt động, nếu máy chủ từ xa không khả dụng, hàm gọi lại delivery_email không được gọi.

Có cách nào tốt hơn không?!?!

-1

Hãy thử như sau:

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

Đó không hoạt động. Nó có một chút với công việc trì hoãn xử lý email. Nó gọi phương thức gửi thư của bạn sau đó gọi giao hàng (hoặc deliver_now) trên đó. Vì vậy, việc phân phối thực sự được thực hiện bên ngoài thư rác! phương pháp –

+0

Tôi cũng muốn một cái gì đó hoạt động mà không cần phải nhớ để thực hiện nó trên mỗi phương pháp bưu phẩm hoặc chagne tất cả các phương pháp bưu phẩm hiện tại của tôi (có khoảng 30) –

0

Các thông điệp debug bạn thấy có ý nghĩa hoàn hảo - hành động bưu phẩm kết thúc ngay lập tức vì hành động gửi thư chính nó là không đồng bộ, xử lý bởi công việc hoãn trong một quá trình hoàn toàn khác nhau. Vì vậy, không có cách nào mà lớp gửi thư có thể biết cách hành động gửi thư kết thúc.

Điều tôi nghĩ bạn cần thay thế là triển khai Delayed job hooks. Bạn sẽ phải viết lại bưu phẩm của bạn và các cuộc gọi để gửi email một chút mặc dù.

tôi đã không kiểm tra nó hoàn toàn nhưng một cái gì đó dọc theo dòng sau đây nên làm việc:

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 là một custom job để được điều hành bởi công việc bị trì hoãn.Tôi cố gắng làm cho nó càng chung càng tốt, vì vậy nó chấp nhận lớp thư, hành động gửi thư, người nhận (thường là người dùng) và các tham số tùy chọn khác. Ngoài ra, yêu cầu phải có recipient để có liên kết emails.

Công việc có hai móc được xác định: success khi hành động gửi thư thành công tạo bản ghi email trong cơ sở dữ liệu và một bản ghi khác cho lỗi đăng nhập. Việc gửi thực tế được thực hiện theo phương thức perform. Lưu ý rằng bên trong nó, phương thức delayed không được sử dụng vì toàn bộ công việc đã được sắp xếp trong một hàng nền Lệnh hoãn công việc bị trì hoãn khi được gọi.

Để gửi thư bằng công việc tùy chỉnh này bạn phải enqueue nó để trì hoãn việc, ví dụ .:

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

đồng nghiệp của tôi đề nghị này. Tôi nghĩ rằng đó là một ý tưởng khá hay, nhưng tôi sẽ mở rộng chức năng của Delayed :: PerformableMailer (https://github.com/collectiveidea/delayed_job/blob/v4.1.1/lib/delayed/performable_mailer.rb). Tôi nghĩ bạn sai về hành động gửi thư không đồng bộ. Bạn đúng từ nơi tôi gọi UserMailer.delay.spam! phương thức mail xảy ra sau đó, nhưng công việc thực tế của việc gửi email là đồng bộ trong công việc bị trì hoãn. –

+0

Tôi có nghĩa là "không đồng bộ" theo nghĩa là hành động gửi thư không chờ kết quả của việc gửi thư thực tế (được thực hiện bởi công việc bị trì hoãn). Và tôi xin lỗi, nhưng tôi không hoàn toàn hiểu bạn đang gặp vấn đề gì với phương pháp móc nối? Từ [source] (https://github.com/collectiveidea/delayed_job/blob/2014009496dd0b2af217ab322f74f91fe4e26097/lib/delayed/message_sending.rb#L2) có vẻ như nội bộ PerformableMailer không là gì ngoài một lớp làm cho việc gửi thư trở nên khá nhiều giống như câu trả lời của tôi ở trên. – BoraMa

+1

Tại sao lại là downvote? – BoraMa

Các vấn đề liên quan