Permalink
Browse files

Action Mailer async flag is true by default using a Synchronous impl

  • Loading branch information...
1 parent b4b5971 commit 34b23e7110a3a13cf157608cefc9b5701017bf39 @spastorino spastorino committed Sep 10, 2012
@@ -1,41 +0,0 @@
-require 'delegate'
-
-module ActionMailer
- module Async
- def method_missing(method_name, *args)
- if action_methods.include?(method_name.to_s)
- QueuedMessage.new(queue, self, method_name, *args)
- else
- super
- end
- end
-
- def queue
- Rails.queue
- end
-
- class QueuedMessage < ::Delegator
- attr_reader :queue
-
- def initialize(queue, mailer_class, method_name, *args)
- @queue = queue
- @mailer_class = mailer_class
- @method_name = method_name
- @args = args
- end
-
- def __getobj__
- @actual_message ||= @mailer_class.send(:new, @method_name, *@args).message
- end
-
- def run
- __getobj__.deliver
- end
-
- # Will push the message onto the Queue to be processed
- def deliver
- @queue << self
- end
- end
- end
-end
@@ -1,4 +1,5 @@
require 'mail'
+require 'action_mailer/queued_message'
require 'action_mailer/collector'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/hash/except'
@@ -464,19 +465,6 @@ def respond_to?(method, include_private = false) #:nodoc:
super || action_methods.include?(method.to_s)
end
- # Will force ActionMailer to push new messages to the queue defined
- # in the ActionMailer class when set to true.
- #
- # class WelcomeMailer < ActionMailer::Base
- # self.async = true
- # end
- def async=(truth)
- if truth
- require 'action_mailer/async'
- extend ActionMailer::Async
- end
- end
-
protected
def set_payload_for_mail(payload, mail) #:nodoc:
@@ -491,10 +479,18 @@ def set_payload_for_mail(payload, mail) #:nodoc:
payload[:mail] = mail.encoded
end
- def method_missing(method, *args) #:nodoc:
- return super unless respond_to?(method)
- new(method, *args).message
+ def method_missing(method_name, *args)
+ if action_methods.include?(method_name.to_s)
+ QueuedMessage.new(queue, self, method_name, *args)
+ else
+ super
+ end
end
+
+ def queue
+ Rails.queue
+ end
+
end
attr_internal :message
@@ -0,0 +1,27 @@
+require 'delegate'
+
+module ActionMailer
+ class QueuedMessage < ::Delegator
+ attr_reader :queue
+
+ def initialize(queue, mailer_class, method_name, *args)
+ @queue = queue
+ @mailer_class = mailer_class
+ @method_name = method_name
+ @args = args
+ end
+
+ def __getobj__
+ @actual_message ||= @mailer_class.send(:new, @method_name, *@args).message
+ end
+
+ def run
+ __getobj__.deliver
+ end
+
+ # Will push the message onto the Queue to be processed
+ def deliver
+ @queue << self
+ end
+ end
+end
@@ -11,6 +11,7 @@
require 'minitest/autorun'
require 'action_mailer'
require 'action_mailer/test_case'
+require 'rails/queueing'
silence_warnings do
# These external dependencies have warnings :/
@@ -27,6 +28,14 @@
FIXTURE_LOAD_PATH = File.expand_path('fixtures', File.dirname(__FILE__))
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
+class ActionMailer::Base < AbstractController::Base
+ class << self
+ def queue
+ @queue ||= Rails::Queueing::Container.new(Rails::Queueing::SynchronousQueue.new)
+ end
+ end
+end
+
class MockSMTP
def self.deliveries
@@deliveries
@@ -575,11 +575,11 @@ def self.delivering_email(mail)
end
test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do
- mail1 = ProcMailer.welcome
+ mail1 = ProcMailer.welcome['X-Proc-Method']
yesterday = 1.day.ago
Time.stubs(:now).returns(yesterday)
- mail2 = ProcMailer.welcome
- assert(mail1['X-Proc-Method'].to_s.to_i > mail2['X-Proc-Method'].to_s.to_i)
+ mail2 = ProcMailer.welcome['X-Proc-Method']
+ assert(mail1.to_s.to_i > mail2.to_s.to_i)
end
test "we can call other defined methods on the class as needed" do
@@ -1,3 +1,2 @@
class AsyncMailer < BaseMailer
- self.async = true
end
@@ -472,7 +472,6 @@ The following configuration options are best made in one of the environment file
|+delivery_method+|Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, <tt>:file</tt> and <tt>:test</tt>.|
|+perform_deliveries+|Determines whether deliveries are actually carried out when the +deliver+ method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.|
|+deliveries+|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.|
-|+async+|Setting this flag will turn on asynchronous message sending, message rendering and delivery will be pushed to <tt>Rails.queue</tt> for processing.|
|+default_options+|Allows you to set default values for the <tt>mail</tt> method options (<tt>:from</tt>, <tt>:reply_to</tt>, etc.).|
h4. Example Action Mailer Configuration
@@ -535,19 +534,7 @@ In the test we send the email and store the returned object in the +email+ varia
h3. Asynchronous
-You can turn on application-wide asynchronous message sending by adding to your <tt>config/application.rb</tt> file:
-
-<ruby>
-config.action_mailer.async = true
-</ruby>
-
-Alternatively you can turn on async within specific mailers:
-
-<ruby>
-class WelcomeMailer < ActionMailer::Base
- self.async = true
-end
-</ruby>
+Rails provides a Synchronous Queue by default. If you want to use an Asynchronous one you will need to configure an async Queue provider like Resque. Queue providers are supposed to have a Railtie where they configure it's own async queue.
h4. Custom Queues
@@ -41,7 +41,7 @@ def initialize(*)
@exceptions_app = nil
@autoflush_log = true
@log_formatter = ActiveSupport::Logger::SimpleFormatter.new
- @queue = Rails::Queueing::Queue
+ @queue = Rails::Queueing::SynchronousQueue
@queue_consumer = Rails::Queueing::ThreadedConsumer
@eager_load = nil
@@ -59,8 +59,5 @@ class Application < Rails::Application
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
<% end -%>
-
- # Enable app-wide asynchronous ActionMailer.
- # config.action_mailer.async = true
end
end
@@ -35,6 +35,14 @@ def []=(queue_name, queue)
class Queue < ::Queue
end
+ class SynchronousQueue < ::Queue
+ def push(job)
+ job.run
+ end
+ alias << push
+ alias enq push
+ end
+
# In test mode, the Rails queue is backed by an Array so that assertions
# can be made about its contents. The test queue provides a +jobs+
# method to make assertions about the queue's contents and a +drain+

2 comments on commit 34b23e7

@arunagw
Member

Build failed by this, I think mock is not picking up properly.

  1) Error:
test_assert_select_email(AssertSelectTest):
NoMethodError: undefined method `queue' for Rails:Module
    /Users/arunagw/checkouts/rails/actionmailer/lib/action_mailer/base.rb:491:in `queue'
    /Users/arunagw/checkouts/rails/actionmailer/lib/action_mailer/base.rb:484:in `method_missing'
    /Users/arunagw/checkouts/rails/actionpack/test/controller/assert_select_test.rb:319:in `test_assert_select_email'

  2) Error:
test_assert_select_email_multipart(AssertSelectTest):
NoMethodError: undefined method `queue' for Rails:Module
    /Users/arunagw/checkouts/rails/actionmailer/lib/action_mailer/base.rb:491:in `queue'
    /Users/arunagw/checkouts/rails/actionmailer/lib/action_mailer/base.rb:484:in `method_missing'
    /Users/arunagw/checkouts/rails/actionpack/test/controller/assert_select_test.rb:329:in `test_assert_select_email_multipart'

3949 tests, 16952 assertions, 0 failures, 2 errors, 0 skips
rake aborted!
Command failed with status (1): [/Users/arunagw/.rvm/rubies/ruby-1.9.3-p194...]

@arunagw
Member

I did a PR here #7612 for above fix.

Please sign in to comment.