ActionMailer observers not working with delayed_job - ruby-on-rails

I have an ActionMailer observer that's working just fine during normal sends, but when I send the delivery to delayed_job, it doesn't get called at all. Is this a function of delayed_job itself, or something specific with my observer?
Controller:
BulkMailer.delay.blast(recipients, email, template)
Initializer:
ActionMailer::Base.register_observer(MailObserver)
Observer
class MailObserver
def self.delivered_email(message)
Rails.logger.debug 'Message: finished'
end
end

The code itself was fine, Delayed Job and ActionMailer observers are compatible. My problem was solved by restarting the workers.

Related

ActionMailer rescue_from failing when called from ActiveJob dispatched to Sidekiq

I use Postmark for sending email and was looking to capture Postmark::InactiveRecipientError which currently just ends up in my dead jobs in my Sidekiq queue. I found on the postmark-rails wiki, what I thought would be the correct course: https://github.com/wildbit/postmark-rails/wiki/Error-Handling
class ApplicationMailer < ActionMailer::Base
default from: "user#stackoverflow.com"
layout 'mailer'
rescue_from Postmark::InactiveRecipientError, with: :reactivate_and_retry
private
def postmark_client
::Postmark::ApiClient.new(Rails.application.credentials.postmark_api_token)
end
def reactivate_and_retry(error)
error.recipients.each do |recipient|
bounce = postmark_client.bounces(emailFilter: recipient).first
next unless bounce
postmark_client.activate_bounce(bounce[:id])
end
# Try again immediately
message.deliver
end
end
When I test the above in development, everything works. My UserMailer goes to Sidekiq which kicks off and correctly activates a suppressed email which I can see the change made via the Postmark interface. However, in production, my jobs are failing with:
undefined method 'reactivate_and_retry' for class '#<Class:UserMailer>'
I haven't been able to find any resources -- this GitHub Issue seems to be a similar problem but doesn't have much for information -- https://github.com/mperham/sidekiq/issues/4161
I am using Rails 6.1.4.4 and Sidekiq 6.4.0.
I am having the same problem. It seems like nobody has this problem.
The problem is that the job calls handle_exception_with_mailer_class and this doesn't have an instance of mailer so it tries to call a class level method. If you define it as a class method it should work though, or use a lambda/block.
https://github.com/rails/rails/blob/cf82c9d7826aa36f2481114961af02dbf39896dd/actionmailer/lib/action_mailer/delivery_job.rb#L37

Best methods for combining Active Job and Action Mailer?

When using Rails Action Mailer, you have the option to use deliver_now to send the email immediately, or deliver_later to send through asynchronously using Active Job. If Active Job is not specified an adapter, it will use an in-process thread pool which would not persist if the server were to stop. Alternatively, I can create a Job to manage my e-mails, which I can then call with perform_now or perform_later, which as I understand is more or less the exact same thing as deliver_now and deliver_later.
My question is, if I specify an adapter, let's say Sidekiq, and then have a database to store my jobs, why would I create a job to handle my e-mails? Is there any additional benefit, or is it an unnecessary step? On a slightly different note, if I did want to create a job for the process, would my email method need to have deliver_now or simply nothing at all? I presume if the e-mail were to say deliver_later, would it knock back the email to the end of the queue and force it wait again until it is sent?
To illustrate, if I have no Job set up to handle my emails, I could simply have:
class UserMailer < ActionMailer::Base
def send_email(user)
mail(to: user.email, subject: "My Subject")
end
end
To call, I would use:
UserMailer.send_email(my_user).deliver_later.
However, if I had wanted to add a job, and both options were called with UserJob.perform_later(user), would my setup be:
class UserJob < ActiveJob::Base
def perform(user)
UserMailer.send_email(user).deliver_now
end
end
Or
def perform(user)
UserMailer.send_email(user)
end
Lastly, I don't think this makes sense, but what would happen if I used:
def perform(user)
UserMailer.send_email(user).deliver_later
end

Delayed_job not sending Rails 3 emails

Note: Using Rails 3.1 and current delayed_job gem.
I have a User model that calls after_create :mail_confirmation.
The mail_confirmation method looks like the following, per the delayed_job instructions:
def mail_confirmation
UserMailer.delay.registration_confirmation(self)
end
The UserMailer is:
class UserMailer < ActionMailer::Base
default from: "test#mysite.com"
def registration_confirmation(user)
#user = user
mail(:to => "#{user.full_name} <#{user.email}>", :subject => "Test registration email")
end
end
The job is queued, and the output from rake jobs:work makes it seem as if it completed successfully:
[Worker(host:mymac.local pid:73694)] Starting job worker
[Worker(host:mymac.local pid:73694)] Class#registration_confirmation completed after 1.3659
[Worker(host:mymac.local pid:73694)] 1 jobs processed at 0.7288 j/s, 0 failed ...
There is no error but the email is never sent. It works fine if I remove delayed from the method call in the User model and go with the standard deliver method:
def mail_confirmation
UserMailer.registration_confirmation(self).deliver
end
How can I find out what is happening when the job is processed? Any idea how to fix it?
Update It appears that it is related to this:
NoMethodError with delayed_job (collectiveidea gem)
Yeah i had this same issue. #Clay is correct, there is an issue at the moment: https://github.com/collectiveidea/delayed_job/issues/323
I resolved this problem by reverting back to the previous version of delayed_job.
gem 'delayed_job', '2.1.2'
I'm having the same issues here. I discovered that for some reason the delay method called on Mailer classes is being handled by the method Delayed::MessageSending#delay instead of Delayed::DelayMail#delay which instantiates the right performable (which is PerformableMailer instead of PerformableMethod). It doesn't crash the job because PerformableMethod just calls the method without the deliver.
Take a look at:
delayted_job/lib/delayed/message_sending.rb
delayted_job/lib/delayed/performable_mailer.rb

Delayed_Job - handle_asynchronously with ActionMailer?

So I'm using Delayed Jobs and I'm trying to figure out how to get all of my mailers to be delayed. Right now, I've put handle_asynchronously on all of my action mailer methods… but I don't think that is going to work.
def first_notification(time)
#time = time
mail :to => time.person.email,
:from => "email#example.com",
:subject => "#{time.person.name} wants to say hi"
end
handle_asynchronously :advisor_first_notification, :priority => 20
The reason I don't think this is going to work is because I call it as such:
UserMailer.first_notification(#time).deliver
So how would it handle the .deliver part of this? Right now I get an exception.
EXCEPTION: #<ArgumentError: wrong number of arguments (1 for 0)>
Which makes me feel that something is getting messed up in the deliver aspect.
I would rather not have a separate job file for each email (as I have a lot of them), so what is the proper way to handle this?
The only other option I can think of is to encapsulate the calls into a method within my models and have them have the handle_asynchronously - that way they can call the entire thing at once.
The mailer is a bit tricky... Instead of using the handle_asynchronously syntax:
UserMailer.delay.first_notification(#time)
The 'trick' is having delay() before the mailer method
Further to Jesse's answer, the collectiveidea's fork of delayed_job indicates that you should definitely not use the deliver method at all with Rails 3 Mailer code:
# without delayed_job
Notifier.signup(#user).deliver
# with delayed_job
Notifier.delay.signup(#user)
I've gotten it to work by doing the following:
class MyMailer < ActionMailer::Base
def send_my_mail_method(*args)
MyMailer.my_mail_method(*args).deliver
end
handle_asynchronously :send_my_mail_method
def my_mail_method(*args)
# mail call ...
end
end
I like this way because it allows me to test that delivery happens interactively, without having to do something stupid like mock the delay call.

perform not being called for Delayed Jobs

I'm using delayed_job 2.1.4 from collectiveidea, and it seems the perform method is never called even though the jobs are processed and removed from the queue. Am I missing something?
I'm using Rails 3.0.5 on Heroku
In the Controller:
Delayed::Job.enqueue FacebookJob.new
In the Job class:
class FacebookJob
def initialize
end
def perform
fb_auths = Authentication.where(:provider => 'facebook')
fb_auths.each do |auth|
checkins = FbGraph::User.new('me', :access_token => URI.encode(auth.token)).checkins
if checkins != nil
checkins.each do |checkin|
[...]
end
end
end
end
end
(the whole code: https://gist.github.com/966509)
The simple answer: does DelayedJob know about the Authentication and FBGraph::User classes? If not, you'll see exactly the behavior you describe: the items will be silently removed from the queue.
See this entry in the Delayed Job Wiki in the Delayed Job Wiki.
Try adding 'require authentication' and 'require fb_graph' (or whatever) in your facebook_job.rb file.

Resources