Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow mailer classes to customize the deliver_later queue name #47408

Merged

Conversation

packagethief
Copy link
Contributor

The deliver_later_queue_name is already configurable on ActionMailer::Base, however the value is inherited by all subclasses. Use a class-inheritable attribute instead, so that subclasses can override.

This can be handy if you're using named queues for concurrency control. For example, a queue being processed by many workers can deliver a lot of mail concurrently, which may not be desirable. With a high-volume mailer, too much concurrency can lead to rate-limiting and blocking at mail providers. Using a queue that's assigned fewer workers (or a single worker) is one way to prevent this.

To make this easier, this PR allows the queue used by the default delivery job to be configured on a per-mailer basis.

Example:

class AnnouncementsMailer < ApplicationMailer
  self.deliver_later_queue_name = :throttled_mailer
end

References:

The `deliver_later_queue_name` is already configurable on ActionMailer::Base,
however the value is inherited by all subclasses. Use a class-inheritable
attribute instead, so that subclasses can override.

Refs:
- rails#18587 (comment)
@packagethief packagethief force-pushed the jh/action-mailer-deliver-later-queue branch from 45a8c44 to fa17c9a Compare February 15, 2023 18:33
@guilleiguaran guilleiguaran merged commit 9192027 into rails:main Feb 18, 2023
@packagethief packagethief deleted the jh/action-mailer-deliver-later-queue branch February 18, 2023 14:14

included do
class_attribute :delivery_job, default: ::ActionMailer::MailDeliveryJob
class_attribute :deliver_later_queue_name, default: :mailers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@packagethief shouldn't this be default: -> { ActionMailer::Base.deliver_later_queue_name }? Since Rails 6.1 mailers queue is nil / :default instead of :mailers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is defining ActionMailer::Base.deliver_later_queue_name so it can't have a default of itself.

Good catch though @javierav. I'd missed that in the 6.1+ configuration defaults, the value is being set to nil:

if respond_to?(:action_mailer)
action_mailer.deliver_later_queue_name = nil
end

The effect is the same – we changed from a cattr_accessor to a class_attribute, but both had the same default of :mailers. In configurations < 6.1 this will be respected, and in later configurations nillified.

But it means the documentation I added about the :mailers name in this PR is wrong, since that won't be the default in newly-generated configurations. I'll create a new PR to update that 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the documentation in #47519

packagethief added a commit to packagethief/rails that referenced this pull request Feb 27, 2023
…rrent defaults

Since Rails 6.1, the default configuration has been to use Active Job's default
queue, achieved by setting the queue name to `nil`.

Refs:
- rails#47408
- rails#47408 (comment)
extend ActiveSupport::Concern

included do
class_attribute :delivery_job, default: ::ActionMailer::MailDeliveryJob
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we extract this module for two lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seemed clearer at the time to locate all queued-delivery concerns in a single place, but I agree that in retrospect it seems a bit much. Happy to move to ActionMailer::Base if that's preferred.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, I think I'm fine. It is not causing any trouble.

@@ -9,7 +9,10 @@ module ActionMailer
#
# Exceptions are rescued and handled by the mailer class.
class MailDeliveryJob < ActiveJob::Base # :nodoc:
queue_as { ActionMailer::Base.deliver_later_queue_name }
queue_as do
mailer_class = arguments.first.constantize
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not we be calling the mailer_class method here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right. The comment suggested it was specifically for use with exception handling but perhaps that comment can be removed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used to any code that can be executed before the arguments are deserialzied, or that could fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I'll update to use mailer_class then, and adjust the comment for clarity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants