activejob 4.2.0.beta1 → 4.2.0.beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,25 +14,36 @@ end
14
14
 
15
15
  module ActiveJob
16
16
  module QueueAdapters
17
+ # == Resque adapter for Active Job
18
+ #
19
+ # Resque (pronounced like "rescue") is a Redis-backed library for creating
20
+ # background jobs, placing those jobs on multiple queues, and processing
21
+ # them later.
22
+ #
23
+ # Read more about Resque {here}[https://github.com/resque/resque].
24
+ #
25
+ # To use Resque set the queue_adapter config to +:resque+.
26
+ #
27
+ # Rails.application.config.active_job.queue_adapter = :resque
17
28
  class ResqueAdapter
18
29
  class << self
19
- def enqueue(job, *args)
20
- Resque.enqueue_to job.queue_name, JobWrapper, job.name, *args
30
+ def enqueue(job) #:nodoc:
31
+ Resque.enqueue_to job.queue_name, JobWrapper, job.serialize
21
32
  end
22
33
 
23
- def enqueue_at(job, timestamp, *args)
34
+ def enqueue_at(job, timestamp) #:nodoc:
24
35
  unless Resque.respond_to?(:enqueue_at_with_queue)
25
36
  raise NotImplementedError, "To be able to schedule jobs with Resque you need the " \
26
37
  "resque-scheduler gem. Please add it to your Gemfile and run bundle install"
27
38
  end
28
- Resque.enqueue_at_with_queue job.queue_name, timestamp, JobWrapper, job.name, *args
39
+ Resque.enqueue_at_with_queue job.queue_name, timestamp, JobWrapper, job.serialize
29
40
  end
30
41
  end
31
42
 
32
- class JobWrapper
43
+ class JobWrapper #:nodoc:
33
44
  class << self
34
- def perform(job_name, *args)
35
- job_name.constantize.new.execute(*args)
45
+ def perform(job_data)
46
+ Base.execute job_data
36
47
  end
37
48
  end
38
49
  end
@@ -2,32 +2,44 @@ require 'sidekiq'
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
+ # == Sidekiq adapter for Active Job
6
+ #
7
+ # Simple, efficient background processing for Ruby. Sidekiq uses threads to
8
+ # handle many jobs at the same time in the same process. It does not
9
+ # require Rails but will integrate tightly with Rails 3/4 to make
10
+ # background processing dead simple.
11
+ #
12
+ # Read more about Sidekiq {here}[http://sidekiq.org].
13
+ #
14
+ # To use Sidekiq set the queue_adapter config to +:sidekiq+.
15
+ #
16
+ # Rails.application.config.active_job.queue_adapter = :sidekiq
5
17
  class SidekiqAdapter
6
18
  class << self
7
- def enqueue(job, *args)
19
+ def enqueue(job) #:nodoc:
8
20
  #Sidekiq::Client does not support symbols as keys
9
21
  Sidekiq::Client.push \
10
22
  'class' => JobWrapper,
11
23
  'queue' => job.queue_name,
12
- 'args' => [ job, *args ],
24
+ 'args' => [ job.serialize ],
13
25
  'retry' => true
14
26
  end
15
27
 
16
- def enqueue_at(job, timestamp, *args)
28
+ def enqueue_at(job, timestamp) #:nodoc:
17
29
  Sidekiq::Client.push \
18
30
  'class' => JobWrapper,
19
31
  'queue' => job.queue_name,
20
- 'args' => [ job, *args ],
32
+ 'args' => [ job.serialize ],
21
33
  'retry' => true,
22
34
  'at' => timestamp
23
35
  end
24
36
  end
25
37
 
26
- class JobWrapper
38
+ class JobWrapper #:nodoc:
27
39
  include Sidekiq::Worker
28
40
 
29
- def perform(job_name, *args)
30
- job_name.constantize.new.execute(*args)
41
+ def perform(job_data)
42
+ Base.execute job_data
31
43
  end
32
44
  end
33
45
  end
@@ -3,29 +3,41 @@ require 'thread'
3
3
 
4
4
  module ActiveJob
5
5
  module QueueAdapters
6
+ # == Sneakers adapter for Active Job
7
+ #
8
+ # A high-performance RabbitMQ background processing framework for Ruby.
9
+ # Sneakers is being used in production for both I/O and CPU intensive
10
+ # workloads, and have achieved the goals of high-performance and
11
+ # 0-maintenance, as designed.
12
+ #
13
+ # Read more about Sneakers {here}[https://github.com/jondot/sneakers].
14
+ #
15
+ # To use Sneakers set the queue_adapter config to +:sneakers+.
16
+ #
17
+ # Rails.application.config.active_job.queue_adapter = :sneakers
6
18
  class SneakersAdapter
7
19
  @monitor = Monitor.new
8
20
 
9
21
  class << self
10
- def enqueue(job, *args)
22
+ def enqueue(job) #:nodoc:
11
23
  @monitor.synchronize do
12
24
  JobWrapper.from_queue job.queue_name
13
- JobWrapper.enqueue ActiveSupport::JSON.encode([ job.name, *args ])
25
+ JobWrapper.enqueue ActiveSupport::JSON.encode(job.serialize)
14
26
  end
15
27
  end
16
28
 
17
- def enqueue_at(job, timestamp, *args)
29
+ def enqueue_at(job, timestamp) #:nodoc:
18
30
  raise NotImplementedError
19
31
  end
20
32
  end
21
33
 
22
- class JobWrapper
34
+ class JobWrapper #:nodoc:
23
35
  include Sneakers::Worker
24
- from_queue 'active_jobs_default'
36
+ from_queue 'default'
25
37
 
26
38
  def work(msg)
27
- job_name, *args = ActiveSupport::JSON.decode(msg)
28
- job_name.constantize.new.execute(*args)
39
+ job_data = ActiveSupport::JSON.decode(msg)
40
+ Base.execute job_data
29
41
  ack!
30
42
  end
31
43
  end
@@ -2,22 +2,37 @@ require 'sucker_punch'
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
+ # == Sucker Punch adapter for Active Job
6
+ #
7
+ # Sucker Punch is a single-process Ruby asynchronous processing library.
8
+ # It's girl_friday and DSL sugar on top of Celluloid. With Celluloid's
9
+ # actor pattern, we can do asynchronous processing within a single process.
10
+ # This reduces costs of hosting on a service like Heroku along with the
11
+ # memory footprint of having to maintain additional jobs if hosting on
12
+ # a dedicated server. All queues can run within a single Rails/Sinatra
13
+ # process.
14
+ #
15
+ # Read more about Sucker Punch {here}[https://github.com/brandonhilkert/sucker_punch].
16
+ #
17
+ # To use Sucker Punch set the queue_adapter config to +:sucker_punch+.
18
+ #
19
+ # Rails.application.config.active_job.queue_adapter = :sucker_punch
5
20
  class SuckerPunchAdapter
6
21
  class << self
7
- def enqueue(job, *args)
8
- JobWrapper.new.async.perform job, *args
22
+ def enqueue(job) #:nodoc:
23
+ JobWrapper.new.async.perform job.serialize
9
24
  end
10
25
 
11
- def enqueue_at(job, timestamp, *args)
26
+ def enqueue_at(job, timestamp) #:nodoc:
12
27
  raise NotImplementedError
13
28
  end
14
29
  end
15
30
 
16
- class JobWrapper
31
+ class JobWrapper #:nodoc:
17
32
  include SuckerPunch::Job
18
33
 
19
- def perform(job, *args)
20
- job.new.execute(*args)
34
+ def perform(job_data)
35
+ Base.execute job_data
21
36
  end
22
37
  end
23
38
  end
@@ -0,0 +1,46 @@
1
+ module ActiveJob
2
+ module QueueAdapters
3
+ # == Test adapter for Active Job
4
+ #
5
+ # The test adapter should be used only in testing. Along with
6
+ # <tt>ActiveJob::TestCase</tt> and <tt>ActiveJob::TestHelper</tt>
7
+ # it makes a great tool to test your Rails application.
8
+ #
9
+ # To use the test adapter set queue_adapter config to +:test+.
10
+ #
11
+ # Rails.application.config.active_job.queue_adapter = :test
12
+ class TestAdapter
13
+ delegate :name, to: :class
14
+ attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs)
15
+ attr_writer(:enqueued_jobs, :performed_jobs)
16
+
17
+ # Provides a store of all the enqueued jobs with the TestAdapter so you can check them.
18
+ def enqueued_jobs
19
+ @enqueued_jobs ||= []
20
+ end
21
+
22
+ # Provides a store of all the performed jobs with the TestAdapter so you can check them.
23
+ def performed_jobs
24
+ @performed_jobs ||= []
25
+ end
26
+
27
+ def enqueue(job) #:nodoc:
28
+ if perform_enqueued_jobs
29
+ performed_jobs << {job: job.class, args: job.arguments, queue: job.queue_name}
30
+ job.perform_now
31
+ else
32
+ enqueued_jobs << {job: job.class, args: job.arguments, queue: job.queue_name}
33
+ end
34
+ end
35
+
36
+ def enqueue_at(job, timestamp) #:nodoc:
37
+ if perform_enqueued_at_jobs
38
+ performed_jobs << {job: job.class, args: job.arguments, queue: job.queue_name, at: timestamp}
39
+ job.perform_now
40
+ else
41
+ enqueued_jobs << {job: job.class, args: job.arguments, queue: job.queue_name, at: timestamp}
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -6,16 +6,33 @@ module ActiveJob
6
6
  mattr_accessor(:queue_name_prefix)
7
7
  mattr_accessor(:default_queue_name) { "default" }
8
8
 
9
- def queue_as(part_name)
9
+ def queue_as(part_name=nil, &block)
10
+ if block_given?
11
+ self.queue_name = block
12
+ else
13
+ self.queue_name = queue_name_from_part(part_name)
14
+ end
15
+ end
16
+
17
+ def queue_name_from_part(part_name) #:nodoc:
10
18
  queue_name = part_name.to_s.presence || default_queue_name
11
19
  name_parts = [queue_name_prefix.presence, queue_name]
12
- self.queue_name = name_parts.compact.join('_')
20
+ name_parts.compact.join('_')
13
21
  end
14
22
  end
15
23
 
16
24
  included do
17
- class_attribute :queue_name
25
+ class_attribute :queue_name, instance_accessor: false
18
26
  self.queue_name = default_queue_name
19
27
  end
28
+
29
+ # Returns the name of the queue the job will be run on
30
+ def queue_name
31
+ if @queue_name.is_a?(Proc)
32
+ @queue_name = self.class.queue_name_from_part(instance_exec(&@queue_name))
33
+ end
34
+ @queue_name
35
+ end
36
+
20
37
  end
21
38
  end
@@ -0,0 +1,7 @@
1
+ require 'active_support/test_case'
2
+
3
+ module ActiveJob
4
+ class TestCase < ActiveSupport::TestCase
5
+ include ActiveJob::TestHelper
6
+ end
7
+ end
@@ -0,0 +1,196 @@
1
+ module ActiveJob
2
+ # Provides helper methods for testing Active Job
3
+ module TestHelper
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def before_setup
8
+ @old_queue_adapter = queue_adapter
9
+ ActiveJob::Base.queue_adapter = :test
10
+ clear_enqueued_jobs
11
+ clear_performed_jobs
12
+ super
13
+ end
14
+
15
+ def after_teardown
16
+ super
17
+ ActiveJob::Base.queue_adapter = @old_queue_adapter
18
+ end
19
+
20
+ # Asserts that the number of enqueued jobs matches the given number.
21
+ #
22
+ # def test_jobs
23
+ # assert_enqueued_jobs 0
24
+ # HelloJob.perform_later('david')
25
+ # assert_enqueued_jobs 1
26
+ # HelloJob.perform_later('abdelkader')
27
+ # assert_enqueued_jobs 2
28
+ # end
29
+ #
30
+ # If a block is passed, that block should cause the specified number of
31
+ # jobs to be enqueued.
32
+ #
33
+ # def test_jobs_again
34
+ # assert_enqueued_jobs 1 do
35
+ # HelloJob.perform_later('cristian')
36
+ # end
37
+ #
38
+ # assert_enqueued_jobs 2 do
39
+ # HelloJob.perform_later('aaron')
40
+ # HelloJob.perform_later('rafael')
41
+ # end
42
+ # end
43
+ def assert_enqueued_jobs(number)
44
+ if block_given?
45
+ original_count = enqueued_jobs.size
46
+ yield
47
+ new_count = enqueued_jobs.size
48
+ assert_equal original_count + number, new_count,
49
+ "#{number} jobs expected, but #{new_count - original_count} were enqueued"
50
+ else
51
+ enqueued_jobs_size = enqueued_jobs.size
52
+ assert_equal number, enqueued_jobs_size, "#{number} jobs expected, but #{enqueued_jobs_size} were enqueued"
53
+ end
54
+ end
55
+
56
+ # Assert that no job have been enqueued.
57
+ #
58
+ # def test_jobs
59
+ # assert_no_enqueued_jobs
60
+ # HelloJob.perform_later('jeremy')
61
+ # assert_enqueued_jobs 1
62
+ # end
63
+ #
64
+ # If a block is passed, that block should not cause any job to be enqueued.
65
+ #
66
+ # def test_jobs_again
67
+ # assert_no_enqueued_jobs do
68
+ # # No job should be enqueued from this block
69
+ # end
70
+ # end
71
+ #
72
+ # Note: This assertion is simply a shortcut for:
73
+ #
74
+ # assert_enqueued_jobs 0
75
+ def assert_no_enqueued_jobs(&block)
76
+ assert_enqueued_jobs 0, &block
77
+ end
78
+
79
+ # Asserts that the number of performed jobs matches the given number.
80
+ #
81
+ # def test_jobs
82
+ # assert_performed_jobs 0
83
+ # HelloJob.perform_later('xavier')
84
+ # assert_performed_jobs 1
85
+ # HelloJob.perform_later('yves')
86
+ # assert_performed_jobs 2
87
+ # end
88
+ #
89
+ # If a block is passed, that block should cause the specified number of
90
+ # jobs to be performed.
91
+ #
92
+ # def test_jobs_again
93
+ # assert_performed_jobs 1 do
94
+ # HelloJob.perform_later('robin')
95
+ # end
96
+ #
97
+ # assert_performed_jobs 2 do
98
+ # HelloJob.perform_later('carlos')
99
+ # HelloJob.perform_later('sean')
100
+ # end
101
+ # end
102
+ def assert_performed_jobs(number)
103
+ if block_given?
104
+ original_count = performed_jobs.size
105
+ yield
106
+ new_count = performed_jobs.size
107
+ assert_equal original_count + number, new_count,
108
+ "#{number} jobs expected, but #{new_count - original_count} were performed"
109
+ else
110
+ performed_jobs_size = performed_jobs.size
111
+ assert_equal number, performed_jobs_size, "#{number} jobs expected, but #{performed_jobs_size} were performed"
112
+ end
113
+ end
114
+
115
+ # Asserts that no jobs have been performed.
116
+ #
117
+ # def test_jobs
118
+ # assert_no_performed_jobs
119
+ # HelloJob.perform_later('matthew')
120
+ # assert_performed_jobs 1
121
+ # end
122
+ #
123
+ # If a block is passed, that block should not cause any job to be performed.
124
+ #
125
+ # def test_jobs_again
126
+ # assert_no_performed_jobs do
127
+ # # No job should be performed from this block
128
+ # end
129
+ # end
130
+ #
131
+ # Note: This assertion is simply a shortcut for:
132
+ #
133
+ # assert_performed_jobs 0
134
+ def assert_no_performed_jobs(&block)
135
+ assert_performed_jobs 0, &block
136
+ end
137
+
138
+ # Asserts that the job passed in the block has been enqueued with the given arguments.
139
+ #
140
+ # def assert_enqueued_job
141
+ # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do
142
+ # MyJob.perform_later(1,2,3)
143
+ # end
144
+ # end
145
+ def assert_enqueued_with(args = {}, &_block)
146
+ original_enqueued_jobs = enqueued_jobs.dup
147
+ clear_enqueued_jobs
148
+ args.assert_valid_keys(:job, :args, :at, :queue)
149
+ yield
150
+ matching_job = enqueued_jobs.any? do |job|
151
+ args.all? { |key, value| value == job[key] }
152
+ end
153
+ assert matching_job, "No enqueued job found with #{args}"
154
+ ensure
155
+ queue_adapter.enqueued_jobs = original_enqueued_jobs + enqueued_jobs
156
+ end
157
+
158
+ # Asserts that the job passed in the block has been performed with the given arguments.
159
+ #
160
+ # def test_assert_performed_with
161
+ # assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high') do
162
+ # MyJob.perform_later(1,2,3)
163
+ # end
164
+ # end
165
+ def assert_performed_with(args = {}, &_block)
166
+ original_performed_jobs = performed_jobs.dup
167
+ clear_performed_jobs
168
+ args.assert_valid_keys(:job, :args, :at, :queue)
169
+ yield
170
+ matching_job = performed_jobs.any? do |job|
171
+ args.all? { |key, value| value == job[key] }
172
+ end
173
+ assert matching_job, "No performed job found with #{args}"
174
+ ensure
175
+ queue_adapter.performed_jobs = original_performed_jobs + performed_jobs
176
+ end
177
+
178
+ def queue_adapter
179
+ ActiveJob::Base.queue_adapter
180
+ end
181
+
182
+ delegate :enqueued_jobs, :enqueued_jobs=,
183
+ :performed_jobs, :performed_jobs=,
184
+ to: :queue_adapter
185
+
186
+ private
187
+ def clear_enqueued_jobs
188
+ enqueued_jobs.clear
189
+ end
190
+
191
+ def clear_performed_jobs
192
+ performed_jobs.clear
193
+ end
194
+ end
195
+ end
196
+ end