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.
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