Reputation: 32091
In one of my Rails application controllers, I do something like this:
def create
@user = User.create(user_params)
# send welcome email
UserMailer.welcome(@user).deliver_later
end
Now, I've intentionally disabled my Redis server so that I can replicate what would happen in the case that a connection couldn't be made from my app.
Unfortunately, this entire create
request fails with a 500 if the deliver_later
is unable to connect to Redis.
What I'd like is that the request still succeeds, but the mailer fails silently.
How can I accomplish this?
Additional information:
In config/initializers/action_mailer.rb:
rescue_from(Redis::CannotConnectError) do |exception|
Rails.logger.error "Original record not found: #{@serialized_arguments.join(', ')}"
end
This never gets called though on exception. I tried rescue_from(StandardError)
and (Exception)
, but that was never called either.
I'm using sidekiq as my job queue adapter:
config.active_job.queue_adapter = :sidekiq
The 500 error I get is:
Redis::CannotConnectError (Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)):
My UserMailer
is a subclass of ApplicationMailer
which is a subclass of ActionMailer::Base
.
Upvotes: 2
Views: 616
Reputation: 2293
In order to prevent calls to deliver_later
from crashing when Redis is down, we added the following monkey-patch:
# If +raise_delivery_errors+ is false, errors occurring while attempting to
# enqueue the email for delivery will be ignored (for instance, if Redis is
# unreachable). In these cases, the email will never be delivered.
module MessageDeliveryWithSilentQueueingErrors
def deliver_later
super
rescue Redis::CannotConnectError => e
raise if raise_delivery_errors
# Log details of the failed email here
end
def deliver_later!
super
rescue Redis::CannotConnectError => e
raise if raise_delivery_errors
# Log details of the failed email here
end
end
ActionMailer::MessageDelivery.send(:prepend, MessageDeliveryWithSilentQueueingErrors)
Upvotes: 1