activejob_backport 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.md +17 -0
  5. data/lib/active_job.rb +39 -0
  6. data/lib/active_job/arguments.rb +81 -0
  7. data/lib/active_job/base.rb +21 -0
  8. data/lib/active_job/callbacks.rb +144 -0
  9. data/lib/active_job/configured_job.rb +16 -0
  10. data/lib/active_job/core.rb +89 -0
  11. data/lib/active_job/enqueuing.rb +75 -0
  12. data/lib/active_job/execution.rb +41 -0
  13. data/lib/active_job/gem_version.rb +15 -0
  14. data/lib/active_job/logging.rb +121 -0
  15. data/lib/active_job/queue_adapter.rb +29 -0
  16. data/lib/active_job/queue_adapters.rb +17 -0
  17. data/lib/active_job/queue_adapters/backburner_adapter.rb +26 -0
  18. data/lib/active_job/queue_adapters/delayed_job_adapter.rb +23 -0
  19. data/lib/active_job/queue_adapters/inline_adapter.rb +15 -0
  20. data/lib/active_job/queue_adapters/qu_adapter.rb +29 -0
  21. data/lib/active_job/queue_adapters/que_adapter.rb +23 -0
  22. data/lib/active_job/queue_adapters/queue_classic_adapter.rb +40 -0
  23. data/lib/active_job/queue_adapters/resque_adapter.rb +41 -0
  24. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +35 -0
  25. data/lib/active_job/queue_adapters/sneakers_adapter.rb +34 -0
  26. data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +25 -0
  27. data/lib/active_job/queue_adapters/test_adapter.rb +37 -0
  28. data/lib/active_job/queue_name.rb +39 -0
  29. data/lib/active_job/railtie.rb +23 -0
  30. data/lib/active_job/test_case.rb +7 -0
  31. data/lib/active_job/test_helper.rb +196 -0
  32. data/lib/active_job/version.rb +8 -0
  33. data/lib/activejob_backport.rb +1 -0
  34. data/lib/global_id.rb +6 -0
  35. data/lib/global_id/global_id.rb +93 -0
  36. data/lib/global_id/identification.rb +13 -0
  37. data/lib/global_id/locator.rb +83 -0
  38. data/lib/rails/generators/job/job_generator.rb +24 -0
  39. data/lib/rails/generators/job/templates/job.rb +9 -0
  40. 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