rails-four-queueing 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- Copyright 2012 YOURNAME
1
+ Copyright 2012 Phil Cohen
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,10 +1,22 @@
1
- # Rails::Four::Queueing
1
+ # rails-four-queueing
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/phlipper/rails-four-queueing.png)](https://next.travis-ci.org/phlipper/rails-four-queueing)
4
4
 
5
5
  ## Description
6
6
 
7
- It's the Queue from Rails 4, backported to Rails 3.2+ for your Queueing pleasure.
7
+ It's the [Queue from Rails 4](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/queueing.rb), backported to Rails 3.2+ for your Queueing pleasure.
8
+
9
+ > `Rails.queue` is the application's queue. You can push a job onto the queue by:
10
+ >
11
+ > ```
12
+ > Rails.queue.push job
13
+ > ```
14
+ >
15
+ > A job is an object that responds to `#run`. Queue consumers will pop jobs off of the queue and invoke the queue's `run` method.
16
+ >
17
+ > Note that depending on your queue implementation, jobs may not be executed in the same process as they were created in, and are never executed in the same thread as they were created in.
18
+ >
19
+ > If necessary, a queue implementation may need to serialize your job for distribution to another process. The documentation of your queue will specify the requirements for that serialization
8
20
 
9
21
 
10
22
  ## Requirements
@@ -42,34 +54,90 @@ $ gem install rails-four-queueing
42
54
 
43
55
  ## Usage
44
56
 
45
- It's the [Rails 4 Queue](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/queueing.rb):
57
+ The following queueing strategies are provided by default:
58
+
59
+ * `SynchronousQueue`
60
+ * `TestQueue`
61
+
62
+ The following queue consumer strategies are provided by default:
63
+
64
+ * `ThreadedQueueConsumer`
65
+
66
+ The threaded consumer will run jobs in a background thread in development mode or in a VM where running jobs on a thread in production mode makes sense.
67
+
68
+ When the process exits, the consumer pushes a `nil` onto the queue and joins the thread, which will ensure that all jobs are executed before the process finally dies.
69
+
70
+ _Note: In this port, classes that live under the `ActiveSupport::` namespace in Rails 4 have been moved to the `Rails::Four::Queueing::` namespace._
71
+
72
+ ### Configuration
73
+
74
+ Rails will now have the following options available:
75
+
76
+ * `config.queue`
77
+ * `config.queue_consumer`
78
+ * `config.action_mailer.queue`
79
+
80
+ These can be customized in `config/application.rb` or by environment:
81
+
82
+ ```ruby
83
+ # config/environments/production.rb
84
+
85
+ # Default the production mode queue to an synchronous queue. You will probably
86
+ # want to replace this with an out-of-process queueing solution.
87
+ config.queue = Rails::Four::Queue::SynchronousQueue.new
46
88
 
89
+ # You will probably want to change the job queue consumer from the default.
90
+ config.queue_consumer = Rails::Four::Queueing::ThreadedQueueConsumer.new
47
91
  ```
48
- Rails.queue is the application's queue. You can push a job onto
49
- the queue by:
50
92
 
51
- Rails.queue.push job
52
93
 
53
- A job is an object that responds to +run+. Queue consumers will
54
- pop jobs off of the queue and invoke the queue's +run+ method.
94
+ ### ActionMailer
95
+
96
+ Mail delivery from ActionMailer can be processed asynchronously using the Rails.queue.
55
97
 
56
- Note that depending on your queue implementation, jobs may not
57
- be executed in the same process as they were created in, and
58
- are never executed in the same thread as they were created in.
98
+ By default, ActionMailer will use the application default Rails.queue strategy. This can be configured:
59
99
 
60
- If necessary, a queue implementation may need to serialize your
61
- job for distribution to another process. The documentation of
62
- your queue will specify the requirements for that serialization
100
+ ```ruby
101
+ # The queue that will be used to deliver the mail. The queue should expect a job
102
+ # that responds to run.
103
+ config.action_mailer.queue = Rails::Four::Queue::SynchronousQueue.new
63
104
  ```
64
105
 
65
106
 
66
- ## Contributing
107
+ ### Testing
67
108
 
68
- 1. [Fork it](https://github.com/phlipper/rails-four-queueing/fork_select)
69
- 2. Create your feature branch (`git checkout -b my-new-feature`)
70
- 3. Commit your changes (`git commit -am 'Added some feature'`)
71
- 4. Push to the branch (`git push origin my-new-feature`)
72
- 5. [Create a Pull Request](hhttps://github.com/phlipper/rails-four-queueing/pull/new)
109
+ 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` method to drain the queue and run the jobs.
110
+
111
+ Jobs are run in a separate thread to catch mistakes where code assumes that the job is run in the same thread.
112
+
113
+ ```ruby
114
+ # config/environments/test.rb
115
+
116
+ config.queue = Rails::Four::Queueing::TestQueue.new
117
+ ```
118
+
119
+ ### Alternate Providers
120
+
121
+ The Rails Queue implementation is designed to be pluggable and you may want to investigate other queue providers, such as:
122
+
123
+ * [resque-rails](https://github.com/jeremy/resque-rails)
124
+ * [Sidekiq](https://github.com/mperham/sidekiq/tree/rails4)
125
+
126
+
127
+ ## Resources
128
+
129
+ The following are some resources from around the Internet which introduce the Rails Queue:
130
+
131
+ _Note: Many of these are, or will be soon, out of date._
132
+
133
+ * [Ruby on Rails 4.0 Release Notes](http://edgeguides.rubyonrails.org/4_0_release_notes.html)
134
+ * [Rails 4.0 Sneak Peek: Queueing](http://reefpoints.dockyard.com/ruby/2012/06/25/rails-4-sneak-peek-queueing.html)
135
+ * [New in Rails 4.0: Rails Queue](http://www.3magine.com/blog/new-in-rails-4-0-rails-queue/)
136
+
137
+
138
+ ## A note on spelling
139
+
140
+ Yes, there are two spelling options. I defer to research provided by [XKCD](http://xkcd.com/853/).
73
141
 
74
142
 
75
143
  ## Contributors
@@ -77,11 +145,18 @@ your queue will specify the requirements for that serialization
77
145
  Many thanks go to the following who have contributed to making this gem even better:
78
146
 
79
147
  * **[@rails](https://github.com/rails)**
80
- * for making this all possible in the first place
148
+ * for making this all possible in the first place
81
149
  * **[@elskwid](https://github.com/elskwid)**
82
- * for providing the inspiration, and the persperation, to see this through to the bitter end
83
- * **[@phlipper](https://github.com/phlipper)**
84
- * for providing the inspiration, and the persperation, to see this through to the bitter end
150
+ * for providing the inspiration, and the persperation, to see this through to the bitter end
151
+
152
+
153
+ ## Contributing
154
+
155
+ 1. [Fork it](https://github.com/phlipper/rails-four-queueing/fork_select)
156
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
157
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
158
+ 4. Push to the branch (`git push origin my-new-feature`)
159
+ 5. [Create a Pull Request](hhttps://github.com/phlipper/rails-four-queueing/pull/new)
85
160
 
86
161
 
87
162
  ## License
@@ -1,3 +1,12 @@
1
+ require "active_support/concern"
2
+
3
+ $: << File.expand_path("../", __FILE__)
4
+
5
+ require "rails/four/configuration"
6
+ require "rails/four/application"
7
+ require "rails/four/queueing/queue"
8
+ require "rails/four/action_mailer/queued_message"
9
+
1
10
  require "rails/four/queueing/engine"
2
11
 
3
12
  module Rails
@@ -0,0 +1,42 @@
1
+ # Original File: RAILS_ROOT/actionmailer/lib/action_mailer/queued_message.rb
2
+ require 'delegate'
3
+
4
+ module Rails
5
+ module Four
6
+ module ActionMailer
7
+ class QueuedMessage < ::Delegator
8
+ attr_reader :queue
9
+
10
+ def initialize(queue, mailer_class, method_name, *args)
11
+ @queue = queue
12
+ @job = DeliveryJob.new(mailer_class, method_name, args)
13
+ end
14
+
15
+ def __getobj__
16
+ @job.message
17
+ end
18
+
19
+ # Queues the message for delivery.
20
+ def deliver
21
+ tap { @queue.push @job }
22
+ end
23
+
24
+ class DeliveryJob
25
+ def initialize(mailer_class, method_name, args)
26
+ @mailer_class = mailer_class
27
+ @method_name = method_name
28
+ @args = args
29
+ end
30
+
31
+ def message
32
+ @message ||= @mailer_class.send(:new, @method_name, *@args).message
33
+ end
34
+
35
+ def run
36
+ message.deliver
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,7 +1,7 @@
1
1
  module Rails
2
2
  module Four
3
3
  module Application
4
- extend ActiveSupport::Concern
4
+ extend ::ActiveSupport::Concern
5
5
 
6
6
  included do
7
7
  attr_accessor :queue_consumer
@@ -1,7 +1,7 @@
1
1
  module Rails
2
2
  module Four
3
3
  module Configuration
4
- extend ActiveSupport::Concern
4
+ extend ::ActiveSupport::Concern
5
5
 
6
6
  included do
7
7
  attr_accessor :queue, :queue_consumer
@@ -1,6 +1,4 @@
1
1
  require "rails"
2
- require "rails/four/configuration"
3
- require "rails/four/application"
4
2
 
5
3
  module Rails
6
4
  module Four
@@ -24,9 +22,7 @@ module Rails
24
22
  # initialize the configuration instance queue if needed
25
23
  config.after_initialize do |app|
26
24
  unless app.config.instance_variable_get(:"@queue")
27
- app.config.instance_variable_set(
28
- :"@queue", Rails::Four::Queueing::SynchronousQueue.new
29
- )
25
+ app.config.instance_variable_set(:"@queue", SynchronousQueue.new)
30
26
  end
31
27
  end
32
28
 
@@ -34,16 +30,34 @@ module Rails
34
30
  # copied from: railties/lib/rails/application/finisher.rb
35
31
  initializer :activate_queue_consumer, after: "finisher_hook" do |app|
36
32
  if app.config.queue.class == Rails::Four::Queueing::Queue
37
- app.queue_consumer = app.config.queue_consumer ||
38
- app.config.queue.consumer
39
- if app.queue_consumer.respond_to?(:logger=)
40
- app.queue_consumer.logger ||= Rails.logger
41
- end
33
+ app.queue_consumer = app.config.queue_consumer || app.config.queue.consumer
34
+ app.queue_consumer.logger ||= Rails.logger if app.queue_consumer.respond_to?(:logger=)
42
35
  app.queue_consumer.start
43
36
  at_exit { app.queue_consumer.shutdown }
44
37
  end
45
38
  end
46
39
 
40
+ # initialize ActionMailer queue configuration
41
+ config.after_initialize do |app|
42
+ app.config.action_mailer.queue ||= app.queue
43
+ end
44
+
45
+ # enable ActionMailer queued delivery
46
+ ::ActiveSupport.on_load :action_mailer do
47
+ class_attribute :queue
48
+ self.queue = Rails::Four::Queueing::SynchronousQueue.new
49
+
50
+ # override default implementation to provide a QueuedMessage
51
+ # copied from Rails 4
52
+ def self.method_missing(method_name, *args)
53
+ if action_methods.include?(method_name.to_s)
54
+ Rails::Four::ActionMailer::QueuedMessage.new(queue, self, method_name, *args)
55
+ else
56
+ super
57
+ end
58
+ end
59
+ end
60
+
47
61
  end
48
62
  end
49
63
  end
@@ -0,0 +1,110 @@
1
+ # Original File: RAILS_ROOT/activesupport/lib/active_support/queueing.rb
2
+ require "delegate"
3
+ require "thread"
4
+
5
+ module Rails
6
+ module Four
7
+ module Queueing
8
+ # A Queue that simply inherits from STDLIB's Queue. When this
9
+ # queue is used, Rails automatically starts a job runner in a
10
+ # background thread.
11
+ class Queue < ::Queue
12
+ attr_writer :consumer
13
+
14
+ def initialize(consumer_options = {})
15
+ super()
16
+ @consumer_options = consumer_options
17
+ end
18
+
19
+ def consumer
20
+ @consumer ||= ThreadedQueueConsumer.new(self, @consumer_options)
21
+ end
22
+
23
+ # Drain the queue, running all jobs in a different thread. This method
24
+ # may not be available on production queues.
25
+ def drain
26
+ # run the jobs in a separate thread so assumptions of synchronous
27
+ # jobs are caught in test mode.
28
+ consumer.drain
29
+ end
30
+ end
31
+
32
+ class SynchronousQueue < Queue
33
+ def push(job)
34
+ super.tap { drain }
35
+ end
36
+ alias << push
37
+ alias enq push
38
+ end
39
+
40
+ # In test mode, the Rails queue is backed by an Array so that assertions
41
+ # can be made about its contents. The test queue provides a +jobs+
42
+ # method to make assertions about the queue's contents and a +drain+
43
+ # method to drain the queue and run the jobs.
44
+ #
45
+ # Jobs are run in a separate thread to catch mistakes where code
46
+ # assumes that the job is run in the same thread.
47
+ class TestQueue < Queue
48
+ # Get a list of the jobs off this queue. This method may not be
49
+ # available on production queues.
50
+ def jobs
51
+ @que.dup
52
+ end
53
+
54
+ # Marshal and unmarshal job before pushing it onto the queue. This will
55
+ # raise an exception on any attempts in tests to push jobs that can't (or
56
+ # shouldn't) be marshalled.
57
+ def push(job)
58
+ super Marshal.load(Marshal.dump(job))
59
+ end
60
+ end
61
+
62
+ # The threaded consumer will run jobs in a background thread in
63
+ # development mode or in a VM where running jobs on a thread in
64
+ # production mode makes sense.
65
+ #
66
+ # When the process exits, the consumer pushes a nil onto the
67
+ # queue and joins the thread, which will ensure that all jobs
68
+ # are executed before the process finally dies.
69
+ class ThreadedQueueConsumer
70
+ attr_accessor :logger
71
+
72
+ def initialize(queue, options = {})
73
+ @queue = queue
74
+ @logger = options[:logger]
75
+ @fallback_logger = Logger.new($stderr)
76
+ end
77
+
78
+ def start
79
+ @thread = Thread.new { consume }
80
+ self
81
+ end
82
+
83
+ def shutdown
84
+ @queue.push nil
85
+ @thread.join
86
+ end
87
+
88
+ def drain
89
+ @queue.pop.run until @queue.empty?
90
+ end
91
+
92
+ def consume
93
+ while job = @queue.pop
94
+ run job
95
+ end
96
+ end
97
+
98
+ def run(job)
99
+ job.run
100
+ rescue Exception => exception
101
+ handle_exception job, exception
102
+ end
103
+
104
+ def handle_exception(job, exception)
105
+ (logger || @fallback_logger).error "Job Error: #{job.inspect}\n#{exception.message}\n#{exception.backtrace.join("\n")}"
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -1,7 +1,7 @@
1
1
  module Rails
2
2
  module Four
3
3
  module Queueing
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1 @@
1
+ Welcome
@@ -0,0 +1,22 @@
1
+ # Original File: RAILS_ROOT/actionmailer/test/base_test.rb
2
+ require "support/action_mailer_abstract_unit"
3
+ require "rails-four-queueing"
4
+ require "support/mailers"
5
+
6
+ class BaseTest < ActiveSupport::TestCase
7
+ def teardown
8
+ ActionMailer::Base.asset_host = nil
9
+ ActionMailer::Base.assets_dir = nil
10
+ end
11
+
12
+ test "delivering message asynchronously" do
13
+ AsyncMailer.delivery_method = :test
14
+ AsyncMailer.deliveries.clear
15
+
16
+ AsyncMailer.welcome.deliver
17
+ assert_equal 0, AsyncMailer.deliveries.length
18
+
19
+ AsyncMailer.queue.drain
20
+ assert_equal 1, AsyncMailer.deliveries.length
21
+ end
22
+ end
@@ -1,6 +1,6 @@
1
1
  # Original File: RAILS_ROOT/activesupport/test/queueing/synchronous_queue_test.rb
2
2
  require "support/active_support_abstract_unit"
3
- require "rails/four/queueing"
3
+ require "rails-four-queueing"
4
4
 
5
5
  class SynchronousQueueTest < ActiveSupport::TestCase
6
6
  class Job
@@ -1,6 +1,6 @@
1
1
  # Original File: RAILS_ROOT/activesupport/test/queueing/test_queue_test.rb
2
2
  require "support/active_support_abstract_unit"
3
- require "rails/four/queueing"
3
+ require "rails-four-queueing"
4
4
 
5
5
  class TestQueueTest < ActiveSupport::TestCase
6
6
  def setup
@@ -1,6 +1,6 @@
1
1
  # Original File: RAILS_ROOT/activesupport/test/queueing/threaded_consumer_test.rb
2
2
  require "support/active_support_abstract_unit"
3
- require "rails/four/queueing"
3
+ require "rails-four-queueing"
4
4
  require "active_support/log_subscriber/test_helper"
5
5
 
6
6
  class TestThreadConsumer < ActiveSupport::TestCase
@@ -0,0 +1,35 @@
1
+ require "support/isolation_abstract_unit"
2
+ require 'set'
3
+
4
+ module ApplicationTests
5
+ class FrameworksTest < ActiveSupport::TestCase
6
+ include ActiveSupport::Testing::Isolation
7
+
8
+ def setup
9
+ build_app
10
+ boot_rails
11
+ FileUtils.rm_rf "#{app_path}/config/environments"
12
+ end
13
+
14
+ def teardown
15
+ teardown_app
16
+ end
17
+
18
+ test "uses the default queue for ActionMailer" do
19
+ require "#{app_path}/config/environment"
20
+ assert_kind_of Rails::Four::Queueing::Queue, ActionMailer::Base.queue
21
+ end
22
+
23
+ test "allows me to configure queue for ActionMailer" do
24
+ app_file "config/environments/development.rb", <<-RUBY
25
+ AppTemplate::Application.configure do
26
+ config.action_mailer.queue = Rails::Four::Queueing::TestQueue.new
27
+ end
28
+ RUBY
29
+
30
+ require "#{app_path}/config/environment"
31
+ assert_kind_of Rails::Four::Queueing::TestQueue, ActionMailer::Base.queue
32
+ end
33
+
34
+ end
35
+ end
@@ -3,23 +3,6 @@ require "support/isolation_abstract_unit"
3
3
  class QueueTest < ActiveSupport::TestCase
4
4
  include ActiveSupport::Testing::Isolation
5
5
 
6
- # overwrite the default `build_app` method to inject the gem for testing
7
- def build_app
8
- super
9
-
10
- # inject the path to the gem we're testing
11
- environment = File.read("#{app_path}/config/application.rb")
12
- if environment =~ /(module AppTemplate)/
13
- rails_four_queueing_path = File.expand_path(
14
- "../../../lib/rails-four-queueing", __FILE__
15
- )
16
- File.open("#{app_path}/config/application.rb", 'w') do |f|
17
- # BOOYA!!
18
- f.puts $` + %Q(\nrequire "#{rails_four_queueing_path}"\n) + $1 + $'
19
- end
20
- end
21
- end
22
-
23
6
  def setup
24
7
  build_app
25
8
  boot_rails
@@ -0,0 +1,65 @@
1
+ # Original File: RAILS_ROOT/actionmailer/test/abstract_unit.rb
2
+ require File.expand_path('../../../../rails/load_paths', __FILE__)
3
+ require 'active_support/core_ext/kernel/reporting'
4
+
5
+ # These are the normal settings that will be set up by Railties
6
+ # TODO: Have these tests support other combinations of these values
7
+ silence_warnings do
8
+ Encoding.default_internal = "UTF-8"
9
+ Encoding.default_external = "UTF-8"
10
+ end
11
+
12
+ require 'minitest/autorun'
13
+ require 'action_mailer'
14
+ require 'action_mailer/test_case'
15
+ require "rails-four-queueing"
16
+
17
+ silence_warnings do
18
+ # These external dependencies have warnings :/
19
+ require 'mail'
20
+ end
21
+
22
+ # Show backtraces for deprecated behavior for quicker cleanup.
23
+ ActiveSupport::Deprecation.debug = true
24
+
25
+ # Bogus template processors
26
+ ActionView::Template.register_template_handler :haml, lambda { |template| "Look its HAML!".inspect }
27
+ ActionView::Template.register_template_handler :bak, lambda { |template| "Lame backup".inspect }
28
+
29
+ FIXTURE_LOAD_PATH = File.expand_path('../fixtures', File.dirname(__FILE__))
30
+ ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
31
+
32
+ class MockSMTP
33
+ def self.deliveries
34
+ @@deliveries
35
+ end
36
+
37
+ def initialize
38
+ @@deliveries = []
39
+ end
40
+
41
+ def sendmail(mail, from, to)
42
+ @@deliveries << [mail, from, to]
43
+ end
44
+
45
+ def start(*args)
46
+ yield self
47
+ end
48
+ end
49
+
50
+ class Net::SMTP
51
+ def self.new(*args)
52
+ MockSMTP.new
53
+ end
54
+ end
55
+
56
+ def set_delivery_method(method)
57
+ @old_delivery_method = ActionMailer::Base.delivery_method
58
+ ActionMailer::Base.delivery_method = method
59
+ end
60
+
61
+ def restore_delivery_method
62
+ ActionMailer::Base.delivery_method = @old_delivery_method
63
+ end
64
+
65
+ ActiveSupport::Deprecation.silenced = true
@@ -23,6 +23,23 @@ require 'tmpdir'
23
23
 
24
24
  module TestHelpers
25
25
  module Paths
26
+ # overwrite the default `build_app` method to inject the gem for testing
27
+ def build_app
28
+ super
29
+
30
+ # inject the path to the gem we're testing
31
+ environment = File.read("#{app_path}/config/application.rb")
32
+ if environment =~ /(module AppTemplate)/
33
+ rails_four_queueing_path = File.expand_path(
34
+ "../../../../lib/rails-four-queueing", __FILE__
35
+ )
36
+ File.open("#{app_path}/config/application.rb", 'w') do |f|
37
+ f.puts $` + %Q(\nrequire "#{rails_four_queueing_path}"\n) + $1 + $'
38
+ end
39
+ end
40
+ end
41
+
42
+
26
43
  def app_template_path
27
44
  File.join Dir.tmpdir, 'app_template'
28
45
  end
@@ -0,0 +1,18 @@
1
+ # Original File: RAILS_ROOT/actionmailer/test/mailers/base_mailer.rb
2
+ class BaseMailer < ActionMailer::Base
3
+ self.mailer_name = "base_mailer"
4
+
5
+ default to: 'system@test.lindsaar.net',
6
+ from: 'jose@test.plataformatec.com',
7
+ reply_to: 'mikel@test.lindsaar.net'
8
+
9
+ def welcome(hash = {})
10
+ headers['X-SPAM'] = "Not SPAM"
11
+ mail({subject: "The first email on new API!"}.merge!(hash))
12
+ end
13
+ end
14
+
15
+ # Original File: RAILS_ROOT/actionmailer/test/mailers/async_mailer.rb
16
+ class AsyncMailer < BaseMailer
17
+ self.queue = Rails::Four::Queueing::TestQueue.new
18
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-four-queueing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-10-29 00:00:00.000000000 Z
13
+ date: 2012-10-31 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -37,26 +37,30 @@ executables: []
37
37
  extensions: []
38
38
  extra_rdoc_files: []
39
39
  files:
40
+ - lib/rails/four/action_mailer/queued_message.rb
40
41
  - lib/rails/four/application.rb
41
42
  - lib/rails/four/configuration.rb
42
43
  - lib/rails/four/queueing/engine.rb
44
+ - lib/rails/four/queueing/queue.rb
43
45
  - lib/rails/four/queueing/version.rb
44
- - lib/rails/four/queueing.rb
45
46
  - lib/rails-four-queueing.rb
46
- - lib/tasks/rails-four-queueing_tasks.rake
47
47
  - MIT-LICENSE
48
48
  - Rakefile
49
49
  - README.md
50
50
  - test/ci/before_script.sh
51
+ - test/fixtures/async_mailer/welcome.erb
52
+ - test/rails/four/actionmailer/base_test.rb
51
53
  - test/rails/four/queueing/synchronous_queue_test.rb
52
54
  - test/rails/four/queueing/test_queue_test.rb
53
55
  - test/rails/four/queueing/threaded_consumer_test.rb
54
- - test/rails/initializers/frameworks_test.rb
56
+ - test/rails/frameworks_test.rb
55
57
  - test/rails/queue_test.rb
56
58
  - test/rails-four-queueing_test.rb
59
+ - test/support/action_mailer_abstract_unit.rb
57
60
  - test/support/active_support_abstract_unit.rb
58
61
  - test/support/empty_bool.rb
59
62
  - test/support/isolation_abstract_unit.rb
63
+ - test/support/mailers.rb
60
64
  homepage: http://phlippers.net/rails-four-queueing
61
65
  licenses: []
62
66
  post_install_message:
@@ -71,7 +75,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
71
75
  version: '0'
72
76
  segments:
73
77
  - 0
74
- hash: -2226372685420353224
78
+ hash: -2324722735646449586
75
79
  required_rubygems_version: !ruby/object:Gem::Requirement
76
80
  none: false
77
81
  requirements:
@@ -80,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
84
  version: '0'
81
85
  segments:
82
86
  - 0
83
- hash: -2226372685420353224
87
+ hash: -2324722735646449586
84
88
  requirements: []
85
89
  rubyforge_project:
86
90
  rubygems_version: 1.8.24
@@ -89,12 +93,16 @@ specification_version: 3
89
93
  summary: It's the Queue from Rails 4, backported to Rails 3.2+ for your Queueing pleasure.
90
94
  test_files:
91
95
  - test/ci/before_script.sh
96
+ - test/fixtures/async_mailer/welcome.erb
97
+ - test/rails/four/actionmailer/base_test.rb
92
98
  - test/rails/four/queueing/synchronous_queue_test.rb
93
99
  - test/rails/four/queueing/test_queue_test.rb
94
100
  - test/rails/four/queueing/threaded_consumer_test.rb
95
- - test/rails/initializers/frameworks_test.rb
101
+ - test/rails/frameworks_test.rb
96
102
  - test/rails/queue_test.rb
97
103
  - test/rails-four-queueing_test.rb
104
+ - test/support/action_mailer_abstract_unit.rb
98
105
  - test/support/active_support_abstract_unit.rb
99
106
  - test/support/empty_bool.rb
100
107
  - test/support/isolation_abstract_unit.rb
108
+ - test/support/mailers.rb
@@ -1,106 +0,0 @@
1
- # Original File: RAILS_ROOT/activesupport/lib/active_support/queueing.rb
2
- require "delegate"
3
- require "thread"
4
-
5
- module Rails::Four::Queueing
6
- # A Queue that simply inherits from STDLIB's Queue. When this
7
- # queue is used, Rails automatically starts a job runner in a
8
- # background thread.
9
- class Queue < ::Queue
10
- attr_writer :consumer
11
-
12
- def initialize(consumer_options = {})
13
- super()
14
- @consumer_options = consumer_options
15
- end
16
-
17
- def consumer
18
- @consumer ||= ThreadedQueueConsumer.new(self, @consumer_options)
19
- end
20
-
21
- # Drain the queue, running all jobs in a different thread. This method
22
- # may not be available on production queues.
23
- def drain
24
- # run the jobs in a separate thread so assumptions of synchronous
25
- # jobs are caught in test mode.
26
- consumer.drain
27
- end
28
- end
29
-
30
- class SynchronousQueue < Queue
31
- def push(job)
32
- super.tap { drain }
33
- end
34
- alias << push
35
- alias enq push
36
- end
37
-
38
- # In test mode, the Rails queue is backed by an Array so that assertions
39
- # can be made about its contents. The test queue provides a +jobs+
40
- # method to make assertions about the queue's contents and a +drain+
41
- # method to drain the queue and run the jobs.
42
- #
43
- # Jobs are run in a separate thread to catch mistakes where code
44
- # assumes that the job is run in the same thread.
45
- class TestQueue < Queue
46
- # Get a list of the jobs off this queue. This method may not be
47
- # available on production queues.
48
- def jobs
49
- @que.dup
50
- end
51
-
52
- # Marshal and unmarshal job before pushing it onto the queue. This will
53
- # raise an exception on any attempts in tests to push jobs that can't (or
54
- # shouldn't) be marshalled.
55
- def push(job)
56
- super Marshal.load(Marshal.dump(job))
57
- end
58
- end
59
-
60
- # The threaded consumer will run jobs in a background thread in
61
- # development mode or in a VM where running jobs on a thread in
62
- # production mode makes sense.
63
- #
64
- # When the process exits, the consumer pushes a nil onto the
65
- # queue and joins the thread, which will ensure that all jobs
66
- # are executed before the process finally dies.
67
- class ThreadedQueueConsumer
68
- attr_accessor :logger
69
-
70
- def initialize(queue, options = {})
71
- @queue = queue
72
- @logger = options[:logger]
73
- @fallback_logger = Logger.new($stderr)
74
- end
75
-
76
- def start
77
- @thread = Thread.new { consume }
78
- self
79
- end
80
-
81
- def shutdown
82
- @queue.push nil
83
- @thread.join
84
- end
85
-
86
- def drain
87
- @queue.pop.run until @queue.empty?
88
- end
89
-
90
- def consume
91
- while job = @queue.pop
92
- run job
93
- end
94
- end
95
-
96
- def run(job)
97
- job.run
98
- rescue Exception => exception
99
- handle_exception job, exception
100
- end
101
-
102
- def handle_exception(job, exception)
103
- (logger || @fallback_logger).error "Job Error: #{job.inspect}\n#{exception.message}\n#{exception.backtrace.join("\n")}"
104
- end
105
- end
106
- end
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :rails-four-queueing do
3
- # # Task goes here
4
- # end
@@ -1,247 +0,0 @@
1
- # require "isolation/abstract_unit"
2
- # require 'set'
3
-
4
- # module ApplicationTests
5
- # class FrameworksTest < ActiveSupport::TestCase
6
- # include ActiveSupport::Testing::Isolation
7
-
8
- # def setup
9
- # build_app
10
- # boot_rails
11
- # FileUtils.rm_rf "#{app_path}/config/environments"
12
- # end
13
-
14
- # def teardown
15
- # teardown_app
16
- # end
17
-
18
- # # AC & AM
19
- # test "set load paths set only if action controller or action mailer are in use" do
20
- # assert_nothing_raised NameError do
21
- # add_to_config <<-RUBY
22
- # config.root = "#{app_path}"
23
- # RUBY
24
-
25
- # use_frameworks []
26
- # require "#{app_path}/config/environment"
27
- # end
28
- # end
29
-
30
- # test "sets action_controller and action_mailer load paths" do
31
- # add_to_config <<-RUBY
32
- # config.root = "#{app_path}"
33
- # RUBY
34
-
35
- # require "#{app_path}/config/environment"
36
-
37
- # expanded_path = File.expand_path("app/views", app_path)
38
- # assert_equal ActionController::Base.view_paths[0].to_s, expanded_path
39
- # assert_equal ActionMailer::Base.view_paths[0].to_s, expanded_path
40
- # end
41
-
42
- # test "allows me to configure default url options for ActionMailer" do
43
- # app_file "config/environments/development.rb", <<-RUBY
44
- # AppTemplate::Application.configure do
45
- # config.action_mailer.default_url_options = { :host => "test.rails" }
46
- # end
47
- # RUBY
48
-
49
- # require "#{app_path}/config/environment"
50
- # assert_equal "test.rails", ActionMailer::Base.default_url_options[:host]
51
- # end
52
-
53
- # test "uses the default queue for ActionMailer" do
54
- # require "#{app_path}/config/environment"
55
- # assert_kind_of ActiveSupport::Queue, ActionMailer::Base.queue
56
- # end
57
-
58
- # test "allows me to configure queue for ActionMailer" do
59
- # app_file "config/environments/development.rb", <<-RUBY
60
- # AppTemplate::Application.configure do
61
- # config.action_mailer.queue = ActiveSupport::TestQueue.new
62
- # end
63
- # RUBY
64
-
65
- # require "#{app_path}/config/environment"
66
- # assert_kind_of ActiveSupport::TestQueue, ActionMailer::Base.queue
67
- # end
68
-
69
- # test "does not include url helpers as action methods" do
70
- # app_file "config/routes.rb", <<-RUBY
71
- # AppTemplate::Application.routes.draw do
72
- # get "/foo", :to => lambda { |env| [200, {}, []] }, :as => :foo
73
- # end
74
- # RUBY
75
-
76
- # app_file "app/mailers/foo.rb", <<-RUBY
77
- # class Foo < ActionMailer::Base
78
- # def notify
79
- # end
80
- # end
81
- # RUBY
82
-
83
- # require "#{app_path}/config/environment"
84
- # assert Foo.method_defined?(:foo_path)
85
- # assert Foo.method_defined?(:main_app)
86
- # assert_equal Set.new(["notify"]), Foo.action_methods
87
- # end
88
-
89
- # test "allows to not load all helpers for controllers" do
90
- # add_to_config "config.action_controller.include_all_helpers = false"
91
-
92
- # app_file "app/controllers/application_controller.rb", <<-RUBY
93
- # class ApplicationController < ActionController::Base
94
- # end
95
- # RUBY
96
-
97
- # app_file "app/controllers/foo_controller.rb", <<-RUBY
98
- # class FooController < ApplicationController
99
- # def included_helpers
100
- # render :inline => "<%= from_app_helper -%> <%= from_foo_helper %>"
101
- # end
102
-
103
- # def not_included_helper
104
- # render :inline => "<%= respond_to?(:from_bar_helper) -%>"
105
- # end
106
- # end
107
- # RUBY
108
-
109
- # app_file "app/helpers/application_helper.rb", <<-RUBY
110
- # module ApplicationHelper
111
- # def from_app_helper
112
- # "from_app_helper"
113
- # end
114
- # end
115
- # RUBY
116
-
117
- # app_file "app/helpers/foo_helper.rb", <<-RUBY
118
- # module FooHelper
119
- # def from_foo_helper
120
- # "from_foo_helper"
121
- # end
122
- # end
123
- # RUBY
124
-
125
- # app_file "app/helpers/bar_helper.rb", <<-RUBY
126
- # module BarHelper
127
- # def from_bar_helper
128
- # "from_bar_helper"
129
- # end
130
- # end
131
- # RUBY
132
-
133
- # app_file "config/routes.rb", <<-RUBY
134
- # AppTemplate::Application.routes.draw do
135
- # get "/:controller(/:action)"
136
- # end
137
- # RUBY
138
-
139
- # require 'rack/test'
140
- # extend Rack::Test::Methods
141
-
142
- # get "/foo/included_helpers"
143
- # assert_equal "from_app_helper from_foo_helper", last_response.body
144
-
145
- # get "/foo/not_included_helper"
146
- # assert_equal "false", last_response.body
147
- # end
148
-
149
- # # AD
150
- # test "action_dispatch extensions are applied to ActionDispatch" do
151
- # add_to_config "config.action_dispatch.tld_length = 2"
152
- # require "#{app_path}/config/environment"
153
- # assert_equal 2, ActionDispatch::Http::URL.tld_length
154
- # end
155
-
156
- # test "assignment config.encoding to default_charset" do
157
- # charset = 'Shift_JIS'
158
- # add_to_config "config.encoding = '#{charset}'"
159
- # require "#{app_path}/config/environment"
160
- # assert_equal charset, ActionDispatch::Response.default_charset
161
- # end
162
-
163
- # # AS
164
- # test "if there's no config.active_support.bare, all of ActiveSupport is required" do
165
- # use_frameworks []
166
- # require "#{app_path}/config/environment"
167
- # assert_nothing_raised { [1,2,3].sample }
168
- # end
169
-
170
- # test "config.active_support.bare does not require all of ActiveSupport" do
171
- # add_to_config "config.active_support.bare = true"
172
-
173
- # use_frameworks []
174
-
175
- # Dir.chdir("#{app_path}/app") do
176
- # require "#{app_path}/config/environment"
177
- # assert_raises(NoMethodError) { "hello".exclude? "lo" }
178
- # end
179
- # end
180
-
181
- # # AR
182
- # test "active_record extensions are applied to ActiveRecord" do
183
- # add_to_config "config.active_record.table_name_prefix = 'tbl_'"
184
- # require "#{app_path}/config/environment"
185
- # assert_equal 'tbl_', ActiveRecord::Base.table_name_prefix
186
- # end
187
-
188
- # test "database middleware doesn't initialize when activerecord is not in frameworks" do
189
- # use_frameworks []
190
- # require "#{app_path}/config/environment"
191
- # assert_nil defined?(ActiveRecord::Base)
192
- # end
193
-
194
- # test "use schema cache dump" do
195
- # Dir.chdir(app_path) do
196
- # `rails generate model post title:string;
197
- # bundle exec rake db:migrate db:schema:cache:dump`
198
- # end
199
- # require "#{app_path}/config/environment"
200
- # ActiveRecord::Base.connection.drop_table("posts") # force drop posts table for test.
201
- # assert ActiveRecord::Base.connection.schema_cache.tables["posts"]
202
- # end
203
-
204
- # test "expire schema cache dump" do
205
- # Dir.chdir(app_path) do
206
- # `rails generate model post title:string;
207
- # bundle exec rake db:migrate db:schema:cache:dump db:rollback`
208
- # end
209
- # silence_warnings {
210
- # require "#{app_path}/config/environment"
211
- # assert !ActiveRecord::Base.connection.schema_cache.tables["posts"]
212
- # }
213
- # end
214
-
215
- # test "active record establish_connection uses Rails.env if DATABASE_URL is not set" do
216
- # begin
217
- # require "#{app_path}/config/environment"
218
- # orig_database_url = ENV.delete("DATABASE_URL")
219
- # orig_rails_env, Rails.env = Rails.env, 'development'
220
- # ActiveRecord::Base.establish_connection
221
- # assert ActiveRecord::Base.connection
222
- # assert_match /#{ActiveRecord::Base.configurations[Rails.env]['database']}/, ActiveRecord::Base.connection_config[:database]
223
- # ensure
224
- # ActiveRecord::Base.remove_connection
225
- # ENV["DATABASE_URL"] = orig_database_url if orig_database_url
226
- # Rails.env = orig_rails_env if orig_rails_env
227
- # end
228
- # end
229
-
230
- # test "active record establish_connection uses DATABASE_URL even if Rails.env is set" do
231
- # begin
232
- # require "#{app_path}/config/environment"
233
- # orig_database_url = ENV.delete("DATABASE_URL")
234
- # orig_rails_env, Rails.env = Rails.env, 'development'
235
- # database_url_db_name = "db/database_url_db.sqlite3"
236
- # ENV["DATABASE_URL"] = "sqlite3://:@localhost/#{database_url_db_name}"
237
- # ActiveRecord::Base.establish_connection
238
- # assert ActiveRecord::Base.connection
239
- # assert_match /#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database]
240
- # ensure
241
- # ActiveRecord::Base.remove_connection
242
- # ENV["DATABASE_URL"] = orig_database_url if orig_database_url
243
- # Rails.env = orig_rails_env if orig_rails_env
244
- # end
245
- # end
246
- # end
247
- # end