activejob 4.2.0.beta1 → 4.2.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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