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.
- checksums.yaml +4 -4
- data/README.md +9 -18
- data/lib/active_job.rb +5 -1
- data/lib/active_job/arguments.rb +56 -13
- data/lib/active_job/base.rb +3 -4
- data/lib/active_job/callbacks.rb +8 -8
- data/lib/active_job/configured_job.rb +16 -0
- data/lib/active_job/core.rb +89 -0
- data/lib/active_job/enqueuing.rb +53 -49
- data/lib/active_job/execution.rb +20 -12
- data/lib/active_job/gem_version.rb +2 -2
- data/lib/active_job/logging.rb +25 -13
- data/lib/active_job/queue_adapter.rb +19 -14
- data/lib/active_job/queue_adapters.rb +51 -0
- data/lib/active_job/queue_adapters/backburner_adapter.rb +18 -7
- data/lib/active_job/queue_adapters/delayed_job_adapter.rb +23 -7
- data/lib/active_job/queue_adapters/inline_adapter.rb +11 -3
- data/lib/active_job/queue_adapters/qu_adapter.rb +20 -8
- data/lib/active_job/queue_adapters/que_adapter.rb +19 -7
- data/lib/active_job/queue_adapters/queue_classic_adapter.rb +36 -7
- data/lib/active_job/queue_adapters/resque_adapter.rb +18 -7
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +19 -7
- data/lib/active_job/queue_adapters/sneakers_adapter.rb +19 -7
- data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +21 -6
- data/lib/active_job/queue_adapters/test_adapter.rb +46 -0
- data/lib/active_job/queue_name.rb +20 -3
- data/lib/active_job/test_case.rb +7 -0
- data/lib/active_job/test_helper.rb +196 -0
- data/lib/active_job/version.rb +1 -1
- data/lib/rails/generators/job/job_generator.rb +4 -2
- metadata +24 -5
- data/lib/active_job/identifier.rb +0 -15
@@ -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
|
20
|
-
Resque.enqueue_to job.queue_name, JobWrapper, job.
|
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
|
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.
|
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(
|
35
|
-
|
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
|
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
|
24
|
+
'args' => [ job.serialize ],
|
13
25
|
'retry' => true
|
14
26
|
end
|
15
27
|
|
16
|
-
def enqueue_at(job, timestamp
|
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
|
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(
|
30
|
-
|
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
|
22
|
+
def enqueue(job) #:nodoc:
|
11
23
|
@monitor.synchronize do
|
12
24
|
JobWrapper.from_queue job.queue_name
|
13
|
-
JobWrapper.enqueue ActiveSupport::JSON.encode(
|
25
|
+
JobWrapper.enqueue ActiveSupport::JSON.encode(job.serialize)
|
14
26
|
end
|
15
27
|
end
|
16
28
|
|
17
|
-
def enqueue_at(job, timestamp
|
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 '
|
36
|
+
from_queue 'default'
|
25
37
|
|
26
38
|
def work(msg)
|
27
|
-
|
28
|
-
|
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
|
8
|
-
JobWrapper.new.async.perform job
|
22
|
+
def enqueue(job) #:nodoc:
|
23
|
+
JobWrapper.new.async.perform job.serialize
|
9
24
|
end
|
10
25
|
|
11
|
-
def enqueue_at(job, timestamp
|
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(
|
20
|
-
|
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
|
-
|
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,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
|