activejob_backport 0.0.1
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 +7 -0
- data/CHANGELOG.md +1 -0
- data/MIT-LICENSE +21 -0
- data/README.md +17 -0
- data/lib/active_job.rb +39 -0
- data/lib/active_job/arguments.rb +81 -0
- data/lib/active_job/base.rb +21 -0
- data/lib/active_job/callbacks.rb +144 -0
- data/lib/active_job/configured_job.rb +16 -0
- data/lib/active_job/core.rb +89 -0
- data/lib/active_job/enqueuing.rb +75 -0
- data/lib/active_job/execution.rb +41 -0
- data/lib/active_job/gem_version.rb +15 -0
- data/lib/active_job/logging.rb +121 -0
- data/lib/active_job/queue_adapter.rb +29 -0
- data/lib/active_job/queue_adapters.rb +17 -0
- data/lib/active_job/queue_adapters/backburner_adapter.rb +26 -0
- data/lib/active_job/queue_adapters/delayed_job_adapter.rb +23 -0
- data/lib/active_job/queue_adapters/inline_adapter.rb +15 -0
- data/lib/active_job/queue_adapters/qu_adapter.rb +29 -0
- data/lib/active_job/queue_adapters/que_adapter.rb +23 -0
- data/lib/active_job/queue_adapters/queue_classic_adapter.rb +40 -0
- data/lib/active_job/queue_adapters/resque_adapter.rb +41 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +35 -0
- data/lib/active_job/queue_adapters/sneakers_adapter.rb +34 -0
- data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +25 -0
- data/lib/active_job/queue_adapters/test_adapter.rb +37 -0
- data/lib/active_job/queue_name.rb +39 -0
- data/lib/active_job/railtie.rb +23 -0
- data/lib/active_job/test_case.rb +7 -0
- data/lib/active_job/test_helper.rb +196 -0
- data/lib/active_job/version.rb +8 -0
- data/lib/activejob_backport.rb +1 -0
- data/lib/global_id.rb +6 -0
- data/lib/global_id/global_id.rb +93 -0
- data/lib/global_id/identification.rb +13 -0
- data/lib/global_id/locator.rb +83 -0
- data/lib/rails/generators/job/job_generator.rb +24 -0
- data/lib/rails/generators/job/templates/job.rb +9 -0
- metadata +124 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'active_job/arguments'
|
2
|
+
|
3
|
+
module ActiveJob
|
4
|
+
module Enqueuing
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Push a job onto the queue. The arguments must be legal JSON types
|
9
|
+
# (string, int, float, nil, true, false, hash or array) or
|
10
|
+
# GlobalID::Identification instances. Arbitrary Ruby objects
|
11
|
+
# are not supported.
|
12
|
+
#
|
13
|
+
# Returns an instance of the job class queued with args available in
|
14
|
+
# Job#arguments.
|
15
|
+
def perform_later(*args)
|
16
|
+
job_or_instantiate(*args).enqueue
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
def job_or_instantiate(*args)
|
21
|
+
args.first.is_a?(self) ? args.first : new(*args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Reschedule the job to be re-executed. This is usefull in combination
|
26
|
+
# with the +rescue_from+ option. When you rescue an exception from your job
|
27
|
+
# you can ask Active Job to retry performing your job.
|
28
|
+
#
|
29
|
+
# ==== Options
|
30
|
+
# * <tt>:wait</tt> - Enqueues the job with the specified delay
|
31
|
+
# * <tt>:wait_until</tt> - Enqueues the job at the time specified
|
32
|
+
# * <tt>:queue</tt> - Enqueues the job on the specified queue
|
33
|
+
#
|
34
|
+
# ==== Examples
|
35
|
+
#
|
36
|
+
# class SiteScrapperJob < ActiveJob::Base
|
37
|
+
# rescue_from(ErrorLoadingSite) do
|
38
|
+
# retry_job queue: :low_priority
|
39
|
+
# end
|
40
|
+
# def perform(*args)
|
41
|
+
# # raise ErrorLoadingSite if cannot scrape
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
def retry_job(options={})
|
45
|
+
enqueue options
|
46
|
+
end
|
47
|
+
|
48
|
+
# Equeue the job to be performed by the queue adapter.
|
49
|
+
#
|
50
|
+
# ==== Options
|
51
|
+
# * <tt>:wait</tt> - Enqueues the job with the specified delay
|
52
|
+
# * <tt>:wait_until</tt> - Enqueues the job at the time specified
|
53
|
+
# * <tt>:queue</tt> - Enqueues the job on the specified queue
|
54
|
+
#
|
55
|
+
# ==== Examples
|
56
|
+
#
|
57
|
+
# my_job_instance.enqueue
|
58
|
+
# my_job_instance.enqueue wait: 5.minutes
|
59
|
+
# my_job_instance.enqueue queue: :important
|
60
|
+
# my_job_instance.enqueue wait_until: Date.tomorrow.midnight
|
61
|
+
def enqueue(options={})
|
62
|
+
self.scheduled_at = options[:wait].seconds.from_now.to_f if options[:wait]
|
63
|
+
self.scheduled_at = options[:wait_until].to_f if options[:wait_until]
|
64
|
+
self.queue_name = self.class.queue_name_from_part(options[:queue]) if options[:queue]
|
65
|
+
run_callbacks :enqueue do
|
66
|
+
if self.scheduled_at
|
67
|
+
self.class.queue_adapter.enqueue_at self, self.scheduled_at
|
68
|
+
else
|
69
|
+
self.class.queue_adapter.enqueue self
|
70
|
+
end
|
71
|
+
end
|
72
|
+
self
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'active_support/rescuable'
|
2
|
+
require 'active_job/arguments'
|
3
|
+
|
4
|
+
module ActiveJob
|
5
|
+
module Execution
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include ActiveSupport::Rescuable
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
# Performs the job immediately.
|
11
|
+
#
|
12
|
+
# MyJob.perform_now("mike")
|
13
|
+
#
|
14
|
+
def perform_now(*args)
|
15
|
+
job_or_instantiate(*args).perform_now
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(job_data) #:nodoc:
|
19
|
+
job = deserialize(job_data)
|
20
|
+
job.perform_now
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Performs the job immediately. The job is not sent to the queueing adapter
|
25
|
+
# and will block the execution until it's finished.
|
26
|
+
#
|
27
|
+
# MyJob.new(*args).perform_now
|
28
|
+
def perform_now
|
29
|
+
deserialize_arguments_if_needed
|
30
|
+
run_callbacks :perform do
|
31
|
+
perform(*arguments)
|
32
|
+
end
|
33
|
+
rescue => exception
|
34
|
+
rescue_with_handler(exception) || raise(exception)
|
35
|
+
end
|
36
|
+
|
37
|
+
def perform(*)
|
38
|
+
fail NotImplementedError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveJob
|
2
|
+
# Returns the version of the currently loaded Active Job as a <tt>Gem::Version</tt>
|
3
|
+
def self.gem_version
|
4
|
+
Gem::Version.new VERSION::STRING
|
5
|
+
end
|
6
|
+
|
7
|
+
module VERSION
|
8
|
+
MAJOR = 0
|
9
|
+
MINOR = 0
|
10
|
+
TINY = 1
|
11
|
+
PRE = nil
|
12
|
+
|
13
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'active_support/core_ext/string/filters'
|
2
|
+
require 'active_support/tagged_logging'
|
3
|
+
require 'active_support/logger'
|
4
|
+
|
5
|
+
module ActiveJob
|
6
|
+
module Logging
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
cattr_accessor(:logger) { ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT)) }
|
11
|
+
|
12
|
+
if ActiveSupport::VERSION::MINOR > 0
|
13
|
+
around_enqueue do |_, block, _|
|
14
|
+
tag_logger do
|
15
|
+
block.call
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
around_perform do |job, block, _|
|
20
|
+
tag_logger(job.class.name, job.job_id) do
|
21
|
+
payload = {adapter: job.class.queue_adapter, job: job}
|
22
|
+
ActiveSupport::Notifications.instrument("perform_start.active_job", payload.dup)
|
23
|
+
ActiveSupport::Notifications.instrument("perform.active_job", payload) do
|
24
|
+
block.call
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
around_enqueue do |_, block|
|
30
|
+
tag_logger do
|
31
|
+
block.call
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
around_perform do |job, block|
|
36
|
+
tag_logger(job.class.name, job.job_id) do
|
37
|
+
payload = {adapter: job.class.queue_adapter, job: job}
|
38
|
+
ActiveSupport::Notifications.instrument("perform_start.active_job", payload.dup)
|
39
|
+
ActiveSupport::Notifications.instrument("perform.active_job", payload) do
|
40
|
+
block.call
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
before_enqueue do |job|
|
47
|
+
if job.scheduled_at
|
48
|
+
ActiveSupport::Notifications.instrument "enqueue_at.active_job",
|
49
|
+
adapter: job.class.queue_adapter, job: job
|
50
|
+
else
|
51
|
+
ActiveSupport::Notifications.instrument "enqueue.active_job",
|
52
|
+
adapter: job.class.queue_adapter, job: job
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def tag_logger(*tags)
|
59
|
+
if logger.respond_to?(:tagged)
|
60
|
+
tags.unshift "ActiveJob" unless logger_tagged_by_active_job?
|
61
|
+
ActiveJob::Base.logger.tagged(*tags){ yield }
|
62
|
+
else
|
63
|
+
yield
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def logger_tagged_by_active_job?
|
68
|
+
logger.formatter.current_tags.include?("ActiveJob")
|
69
|
+
end
|
70
|
+
|
71
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
72
|
+
def enqueue(event)
|
73
|
+
p event.payload
|
74
|
+
info do
|
75
|
+
job = event.payload[:job]
|
76
|
+
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)}" + args_info(job)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def enqueue_at(event)
|
81
|
+
info do
|
82
|
+
job = event.payload[:job]
|
83
|
+
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)}" + args_info(job)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def perform_start(event)
|
88
|
+
info do
|
89
|
+
job = event.payload[:job]
|
90
|
+
"Performing #{job.class.name} from #{queue_name(event)}" + args_info(job)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def perform(event)
|
95
|
+
info do
|
96
|
+
job = event.payload[:job]
|
97
|
+
"Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2).to_s}ms"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
def queue_name(event)
|
103
|
+
event.payload[:adapter].name.demodulize.gsub('Adapter', '') + "(#{event.payload[:job].queue_name})"
|
104
|
+
end
|
105
|
+
|
106
|
+
def args_info(job)
|
107
|
+
job.arguments.any? ? " with arguments: #{job.arguments.map(&:inspect).join(", ")}" : ""
|
108
|
+
end
|
109
|
+
|
110
|
+
def scheduled_at(event)
|
111
|
+
Time.at(event.payload[:job].scheduled_at).utc
|
112
|
+
end
|
113
|
+
|
114
|
+
def logger
|
115
|
+
ActiveJob::Base.logger
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
ActiveJob::Logging::LogSubscriber.attach_to :active_job
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_job/queue_adapters/inline_adapter'
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
3
|
+
|
4
|
+
module ActiveJob
|
5
|
+
module QueueAdapter
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
mattr_reader(:queue_adapter) { ActiveJob::QueueAdapters::InlineAdapter }
|
10
|
+
|
11
|
+
def queue_adapter=(name_or_adapter)
|
12
|
+
@@queue_adapter = \
|
13
|
+
case name_or_adapter
|
14
|
+
when :test
|
15
|
+
ActiveJob::QueueAdapters::TestAdapter.new
|
16
|
+
when Symbol, String
|
17
|
+
load_adapter(name_or_adapter)
|
18
|
+
when Class
|
19
|
+
name_or_adapter
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def load_adapter(name)
|
25
|
+
"ActiveJob::QueueAdapters::#{name.to_s.camelize}Adapter".constantize
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveJob
|
2
|
+
module QueueAdapters
|
3
|
+
extend ActiveSupport::Autoload
|
4
|
+
|
5
|
+
autoload :InlineAdapter
|
6
|
+
autoload :BackburnerAdapter
|
7
|
+
autoload :DelayedJobAdapter
|
8
|
+
autoload :QuAdapter
|
9
|
+
autoload :QueAdapter
|
10
|
+
autoload :QueueClassicAdapter
|
11
|
+
autoload :ResqueAdapter
|
12
|
+
autoload :SidekiqAdapter
|
13
|
+
autoload :SneakersAdapter
|
14
|
+
autoload :SuckerPunchAdapter
|
15
|
+
autoload :TestAdapter
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'backburner'
|
2
|
+
|
3
|
+
module ActiveJob
|
4
|
+
module QueueAdapters
|
5
|
+
class BackburnerAdapter
|
6
|
+
class << self
|
7
|
+
def enqueue(job)
|
8
|
+
Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def enqueue_at(job, timestamp)
|
12
|
+
delay = timestamp - Time.current.to_f
|
13
|
+
Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name, delay: delay
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class JobWrapper
|
18
|
+
class << self
|
19
|
+
def perform(job_data)
|
20
|
+
Base.execute job_data
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'delayed_job'
|
2
|
+
|
3
|
+
module ActiveJob
|
4
|
+
module QueueAdapters
|
5
|
+
class DelayedJobAdapter
|
6
|
+
class << self
|
7
|
+
def enqueue(job)
|
8
|
+
JobWrapper.new.delay(queue: job.queue_name).perform(job.serialize)
|
9
|
+
end
|
10
|
+
|
11
|
+
def enqueue_at(job, timestamp)
|
12
|
+
JobWrapper.new.delay(queue: job.queue_name, run_at: Time.at(timestamp)).perform(job.serialize)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class JobWrapper
|
17
|
+
def perform(job_data)
|
18
|
+
Base.execute(job_data)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveJob
|
2
|
+
module QueueAdapters
|
3
|
+
class InlineAdapter
|
4
|
+
class << self
|
5
|
+
def enqueue(job)
|
6
|
+
Base.execute(job.serialize)
|
7
|
+
end
|
8
|
+
|
9
|
+
def enqueue_at(*)
|
10
|
+
raise NotImplementedError.new("Use a queueing backend to enqueue jobs in the future. Read more at https://github.com/rails/activejob")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'qu'
|
2
|
+
|
3
|
+
module ActiveJob
|
4
|
+
module QueueAdapters
|
5
|
+
class QuAdapter
|
6
|
+
class << self
|
7
|
+
def enqueue(job, *args)
|
8
|
+
Qu::Payload.new(klass: JobWrapper, args: [job.serialize]).tap do |payload|
|
9
|
+
payload.instance_variable_set(:@queue, job.queue_name)
|
10
|
+
end.push
|
11
|
+
end
|
12
|
+
|
13
|
+
def enqueue_at(job, timestamp, *args)
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class JobWrapper < Qu::Job
|
19
|
+
def initialize(job_data)
|
20
|
+
@job_data = job_data
|
21
|
+
end
|
22
|
+
|
23
|
+
def perform
|
24
|
+
Base.execute @job_data
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'que'
|
2
|
+
|
3
|
+
module ActiveJob
|
4
|
+
module QueueAdapters
|
5
|
+
class QueAdapter
|
6
|
+
class << self
|
7
|
+
def enqueue(job)
|
8
|
+
JobWrapper.enqueue job.serialize, queue: job.queue_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def enqueue_at(job, timestamp)
|
12
|
+
JobWrapper.enqueue job.serialize, queue: job.queue_name, run_at: Time.at(timestamp)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class JobWrapper < Que::Job
|
17
|
+
def run(job_data)
|
18
|
+
Base.execute job_data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'queue_classic'
|
2
|
+
|
3
|
+
module ActiveJob
|
4
|
+
module QueueAdapters
|
5
|
+
class QueueClassicAdapter
|
6
|
+
class << self
|
7
|
+
def enqueue(job)
|
8
|
+
build_queue(job.queue_name).enqueue("#{JobWrapper.name}.perform", job.serialize)
|
9
|
+
end
|
10
|
+
|
11
|
+
def enqueue_at(job, timestamp)
|
12
|
+
queue = build_queue(job.queue_name)
|
13
|
+
unless queue.respond_to?(:enqueue_at)
|
14
|
+
raise NotImplementedError, 'To be able to schedule jobs with Queue Classic ' \
|
15
|
+
'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. '
|
16
|
+
'You can implement this yourself or you can use the queue_classic-later gem.'
|
17
|
+
end
|
18
|
+
queue.enqueue_at(timestamp, "#{JobWrapper.name}.perform", job.serialize)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Builds a <tt>QC::Queue</tt> object to schedule jobs on.
|
22
|
+
#
|
23
|
+
# If you have a custom <tt>QC::Queue</tt> subclass you'll need to suclass
|
24
|
+
# <tt>ActiveJob::QueueAdapters::QueueClassicAdapter</tt> and override the
|
25
|
+
# <tt>build_queue</tt> method.
|
26
|
+
def build_queue(queue_name)
|
27
|
+
QC::Queue.new(queue_name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class JobWrapper
|
32
|
+
class << self
|
33
|
+
def perform(job_data)
|
34
|
+
Base.execute job_data
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|