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.
@@ -4,15 +4,29 @@ require 'active_job/arguments'
4
4
  module ActiveJob
5
5
  module Execution
6
6
  extend ActiveSupport::Concern
7
+ include ActiveSupport::Rescuable
7
8
 
8
- included do
9
- include ActiveSupport::Rescuable
10
- end
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
11
17
 
12
- def execute(job_id, *serialized_args)
13
- self.job_id = job_id
14
- self.arguments = deserialize_arguments(serialized_args)
18
+ def execute(job_data) #:nodoc:
19
+ job = deserialize(job_data)
20
+ job.perform_now
21
+ end
22
+ end
15
23
 
24
+ # Performs the job immediately. The job is not sent to the queueing adapter
25
+ # but directly executed by blocking the execution of others until it's finished.
26
+ #
27
+ # MyJob.new(*args).perform_now
28
+ def perform_now
29
+ deserialize_arguments_if_needed
16
30
  run_callbacks :perform do
17
31
  perform(*arguments)
18
32
  end
@@ -23,11 +37,5 @@ module ActiveJob
23
37
  def perform(*)
24
38
  fail NotImplementedError
25
39
  end
26
-
27
- private
28
- def deserialize_arguments(serialized_args)
29
- Arguments.deserialize(serialized_args)
30
- end
31
-
32
40
  end
33
41
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveJob
2
- # Returns the version of the currently loaded ActiveJob as a <tt>Gem::Version</tt>
2
+ # Returns the version of the currently loaded Active Job as a <tt>Gem::Version</tt>
3
3
  def self.gem_version
4
4
  Gem::Version.new VERSION::STRING
5
5
  end
@@ -8,7 +8,7 @@ module ActiveJob
8
8
  MAJOR = 4
9
9
  MINOR = 2
10
10
  TINY = 0
11
- PRE = "beta1"
11
+ PRE = "beta2"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -17,7 +17,7 @@ module ActiveJob
17
17
 
18
18
  around_perform do |job, block, _|
19
19
  tag_logger(job.class.name, job.job_id) do
20
- payload = {adapter: job.class.queue_adapter, job: job.class, args: job.arguments}
20
+ payload = {adapter: job.class.queue_adapter, job: job}
21
21
  ActiveSupport::Notifications.instrument("perform_start.active_job", payload.dup)
22
22
  ActiveSupport::Notifications.instrument("perform.active_job", payload) do
23
23
  block.call
@@ -26,12 +26,12 @@ module ActiveJob
26
26
  end
27
27
 
28
28
  before_enqueue do |job|
29
- if job.enqueued_at
29
+ if job.scheduled_at
30
30
  ActiveSupport::Notifications.instrument "enqueue_at.active_job",
31
- adapter: job.class.queue_adapter, job: job.class, job_id: job.job_id, args: job.arguments, timestamp: job.enqueued_at
31
+ adapter: job.class.queue_adapter, job: job
32
32
  else
33
33
  ActiveSupport::Notifications.instrument "enqueue.active_job",
34
- adapter: job.class.queue_adapter, job: job.class, job_id: job.job_id, args: job.arguments
34
+ adapter: job.class.queue_adapter, job: job
35
35
  end
36
36
  end
37
37
  end
@@ -50,21 +50,33 @@ module ActiveJob
50
50
  logger.formatter.current_tags.include?("ActiveJob")
51
51
  end
52
52
 
53
- class LogSubscriber < ActiveSupport::LogSubscriber
53
+ class LogSubscriber < ActiveSupport::LogSubscriber #:nodoc:
54
54
  def enqueue(event)
55
- info "Enqueued #{event.payload[:job].name} (Job ID: #{event.payload[:job_id]}) to #{queue_name(event)}" + args_info(event)
55
+ info do
56
+ job = event.payload[:job]
57
+ "Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)}" + args_info(job)
58
+ end
56
59
  end
57
60
 
58
61
  def enqueue_at(event)
59
- info "Enqueued #{event.payload[:job].name} (Job ID: #{event.payload[:job_id]}) to #{queue_name(event)} at #{enqueued_at(event)}" + args_info(event)
62
+ info do
63
+ job = event.payload[:job]
64
+ "Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)}" + args_info(job)
65
+ end
60
66
  end
61
67
 
62
68
  def perform_start(event)
63
- info "Performing #{event.payload[:job].name} from #{queue_name(event)}" + args_info(event)
69
+ info do
70
+ job = event.payload[:job]
71
+ "Performing #{job.class.name} from #{queue_name(event)}" + args_info(job)
72
+ end
64
73
  end
65
74
 
66
75
  def perform(event)
67
- info "Performed #{event.payload[:job].name} from #{queue_name(event)} in #{event.duration.round(2).to_s}ms"
76
+ info do
77
+ job = event.payload[:job]
78
+ "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2).to_s}ms"
79
+ end
68
80
  end
69
81
 
70
82
  private
@@ -72,12 +84,12 @@ module ActiveJob
72
84
  event.payload[:adapter].name.demodulize.remove('Adapter') + "(#{event.payload[:job].queue_name})"
73
85
  end
74
86
 
75
- def args_info(event)
76
- event.payload[:args].any? ? " with arguments: #{event.payload[:args].map(&:inspect).join(", ")}" : ""
87
+ def args_info(job)
88
+ job.arguments.any? ? " with arguments: #{job.arguments.map(&:inspect).join(", ")}" : ""
77
89
  end
78
90
 
79
- def enqueued_at(event)
80
- Time.at(event.payload[:timestamp]).utc
91
+ def scheduled_at(event)
92
+ Time.at(event.payload[:job].scheduled_at).utc
81
93
  end
82
94
 
83
95
  def logger
@@ -3,22 +3,27 @@ require 'active_support/core_ext/string/inflections'
3
3
 
4
4
  module ActiveJob
5
5
  module QueueAdapter
6
- mattr_reader(:queue_adapter) { ActiveJob::QueueAdapters::InlineAdapter }
6
+ extend ActiveSupport::Concern
7
7
 
8
- def queue_adapter=(name_or_adapter)
9
- @@queue_adapter = \
10
- case name_or_adapter
11
- when Symbol, String
12
- load_adapter(name_or_adapter)
13
- when Class
14
- name_or_adapter
15
- end
16
- end
8
+ module ClassMethods
9
+ mattr_reader(:queue_adapter) { ActiveJob::QueueAdapters::InlineAdapter }
17
10
 
18
- private
19
- def load_adapter(name)
20
- require "active_job/queue_adapters/#{name}_adapter"
21
- "ActiveJob::QueueAdapters::#{name.to_s.camelize}Adapter".constantize
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
22
21
  end
22
+
23
+ private
24
+ def load_adapter(name)
25
+ "ActiveJob::QueueAdapters::#{name.to_s.camelize}Adapter".constantize
26
+ end
27
+ end
23
28
  end
24
29
  end
@@ -0,0 +1,51 @@
1
+ module ActiveJob
2
+ # == Active Job adapters
3
+ #
4
+ # Active Job has adapters for the following queueing backends:
5
+ #
6
+ # * {Backburner}[https://github.com/nesquena/backburner]
7
+ # * {Delayed Job}[https://github.com/collectiveidea/delayed_job]
8
+ # * {Qu}[https://github.com/bkeepers/qu]
9
+ # * {Que}[https://github.com/chanks/que]
10
+ # * {QueueClassic 2.x}[https://github.com/ryandotsmith/queue_classic/tree/v2.2.3]
11
+ # * {Resque 1.x}[https://github.com/resque/resque/tree/1-x-stable]
12
+ # * {Sidekiq}[http://sidekiq.org]
13
+ # * {Sneakers}[https://github.com/jondot/sneakers]
14
+ # * {Sucker Punch}[https://github.com/brandonhilkert/sucker_punch]
15
+ #
16
+ # #### Backends Features
17
+ #
18
+ # | | Async | Queues | Delayed | Priorities | Timeout | Retries |
19
+ # |-------------------|-------|--------|-----------|------------|---------|---------|
20
+ # | Backburner | Yes | Yes | Yes | Yes | Job | Global |
21
+ # | Delayed Job | Yes | Yes | Yes | Job | Global | Global |
22
+ # | Que | Yes | Yes | Yes | Job | No | Job |
23
+ # | Queue Classic | Yes | Yes | No* | No | No | No |
24
+ # | Resque | Yes | Yes | Yes (Gem) | Queue | Global | Yes |
25
+ # | Sidekiq | Yes | Yes | Yes | Queue | No | Job |
26
+ # | Sneakers | Yes | Yes | No | Queue | Queue | No |
27
+ # | Sucker Punch | Yes | Yes | No | No | No | No |
28
+ # | Active Job Inline | No | Yes | N/A | N/A | N/A | N/A |
29
+ # | Active Job | Yes | Yes | Yes | No | No | No |
30
+ #
31
+ # NOTE:
32
+ # Queue Classic does not support Job scheduling. However you can implement this
33
+ # yourself or you can use the queue_classic-later gem. See the documentation for
34
+ # ActiveJob::QueueAdapters::QueueClassicAdapter.
35
+ #
36
+ module QueueAdapters
37
+ extend ActiveSupport::Autoload
38
+
39
+ autoload :InlineAdapter
40
+ autoload :BackburnerAdapter
41
+ autoload :DelayedJobAdapter
42
+ autoload :QuAdapter
43
+ autoload :QueAdapter
44
+ autoload :QueueClassicAdapter
45
+ autoload :ResqueAdapter
46
+ autoload :SidekiqAdapter
47
+ autoload :SneakersAdapter
48
+ autoload :SuckerPunchAdapter
49
+ autoload :TestAdapter
50
+ end
51
+ end
@@ -2,21 +2,32 @@ require 'backburner'
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
+ # == Backburner adapter for Active Job
6
+ #
7
+ # Backburner is a beanstalkd-powered job queue that can handle a very
8
+ # high volume of jobs. You create background jobs and place them on
9
+ # multiple work queues to be processed later. Read more about
10
+ # Backburner {here}[https://github.com/nesquena/backburner].
11
+ #
12
+ # To use Backburner set the queue_adapter config to +:backburner+.
13
+ #
14
+ # Rails.application.config.active_job.queue_adapter = :backburner
5
15
  class BackburnerAdapter
6
16
  class << self
7
- def enqueue(job, *args)
8
- Backburner::Worker.enqueue JobWrapper, [ job.name, *args ], queue: job.queue_name
17
+ def enqueue(job) #:nodoc:
18
+ Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name
9
19
  end
10
20
 
11
- def enqueue_at(job, timestamp, *args)
12
- raise NotImplementedError
21
+ def enqueue_at(job, timestamp) #:nodoc:
22
+ delay = timestamp - Time.current.to_f
23
+ Backburner::Worker.enqueue JobWrapper, [ job.serialize ], queue: job.queue_name, delay: delay
13
24
  end
14
25
  end
15
26
 
16
- class JobWrapper
27
+ class JobWrapper #:nodoc:
17
28
  class << self
18
- def perform(job_name, *args)
19
- job_name.constantize.new.execute(*args)
29
+ def perform(job_data)
30
+ Base.execute job_data
20
31
  end
21
32
  end
22
33
  end
@@ -2,20 +2,36 @@ require 'delayed_job'
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
+ # == Delayed Job adapter for Active Job
6
+ #
7
+ # Delayed::Job (or DJ) encapsulates the common pattern of asynchronously
8
+ # executing longer tasks in the background. Although DJ can have many
9
+ # storage backends one of the most used is based on Active Record.
10
+ # Read more about Delayed Job {here}[https://github.com/collectiveidea/delayed_job].
11
+ #
12
+ # To use Delayed Job set the queue_adapter config to +:delayed_job+.
13
+ #
14
+ # Rails.application.config.active_job.queue_adapter = :delayed_job
5
15
  class DelayedJobAdapter
6
16
  class << self
7
- def enqueue(job, *args)
8
- JobWrapper.new.delay(queue: job.queue_name).perform(job, *args)
17
+ def enqueue(job) #:nodoc:
18
+ Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name)
9
19
  end
10
20
 
11
- def enqueue_at(job, timestamp, *args)
12
- JobWrapper.new.delay(queue: job.queue_name, run_at: Time.at(timestamp)).perform(job, *args)
21
+ def enqueue_at(job, timestamp) #:nodoc:
22
+ Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, run_at: Time.at(timestamp))
13
23
  end
14
24
  end
15
25
 
16
- class JobWrapper
17
- def perform(job, *args)
18
- job.new.execute(*args)
26
+ class JobWrapper #:nodoc:
27
+ attr_accessor :job_data
28
+
29
+ def initialize(job_data)
30
+ @job_data = job_data
31
+ end
32
+
33
+ def perform
34
+ Base.execute(job_data)
19
35
  end
20
36
  end
21
37
  end
@@ -1,12 +1,20 @@
1
1
  module ActiveJob
2
2
  module QueueAdapters
3
+ # == Active Job Inline adapter
4
+ #
5
+ # When enqueueing jobs with the Inline adapter the job will be executed
6
+ # immediately.
7
+ #
8
+ # To use the Inline set the queue_adapter config to +:inline+.
9
+ #
10
+ # Rails.application.config.active_job.queue_adapter = :inline
3
11
  class InlineAdapter
4
12
  class << self
5
- def enqueue(job, *args)
6
- job.new.execute(*args)
13
+ def enqueue(job) #:nodoc:
14
+ Base.execute(job.serialize)
7
15
  end
8
16
 
9
- def enqueue_at(*)
17
+ def enqueue_at(*) #:nodoc:
10
18
  raise NotImplementedError.new("Use a queueing backend to enqueue jobs in the future. Read more at https://github.com/rails/activejob")
11
19
  end
12
20
  end
@@ -2,27 +2,39 @@ require 'qu'
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
+ # == Qu adapter for Active Job
6
+ #
7
+ # Qu is a Ruby library for queuing and processing background jobs. It is
8
+ # heavily inspired by delayed_job and Resque. Qu was created to overcome
9
+ # some shortcomings in the existing queuing libraries that we experienced.
10
+ # The advantages of Qu are: Multiple backends (redis, mongo), jobs are
11
+ # requeued when worker is killed, resque-like API.
12
+ #
13
+ # Read more about Que {here}[https://github.com/bkeepers/qu].
14
+ #
15
+ # To use Qu set the queue_adapter config to +:qu+.
16
+ #
17
+ # Rails.application.config.active_job.queue_adapter = :qu
5
18
  class QuAdapter
6
19
  class << self
7
- def enqueue(job, *args)
8
- Qu::Payload.new(klass: JobWrapper, args: [job.name, *args]).tap do |payload|
20
+ def enqueue(job, *args) #:nodoc:
21
+ Qu::Payload.new(klass: JobWrapper, args: [job.serialize]).tap do |payload|
9
22
  payload.instance_variable_set(:@queue, job.queue_name)
10
23
  end.push
11
24
  end
12
25
 
13
- def enqueue_at(job, timestamp, *args)
26
+ def enqueue_at(job, timestamp, *args) #:nodoc:
14
27
  raise NotImplementedError
15
28
  end
16
29
  end
17
30
 
18
- class JobWrapper < Qu::Job
19
- def initialize(job_name, *args)
20
- @job = job_name.constantize
21
- @args = args
31
+ class JobWrapper < Qu::Job #:nodoc:
32
+ def initialize(job_data)
33
+ @job_data = job_data
22
34
  end
23
35
 
24
36
  def perform
25
- @job.new.execute(*@args)
37
+ Base.execute @job_data
26
38
  end
27
39
  end
28
40
  end
@@ -2,20 +2,32 @@ require 'que'
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
+ # == Que adapter for Active Job
6
+ #
7
+ # Que is a high-performance alternative to DelayedJob or QueueClassic that
8
+ # improves the reliability of your application by protecting your jobs with
9
+ # the same ACID guarantees as the rest of your data. Que is a queue for
10
+ # Ruby and PostgreSQL that manages jobs using advisory locks.
11
+ #
12
+ # Read more about Que {here}[https://github.com/chanks/que].
13
+ #
14
+ # To use Que set the queue_adapter config to +:que+.
15
+ #
16
+ # Rails.application.config.active_job.queue_adapter = :que
5
17
  class QueAdapter
6
18
  class << self
7
- def enqueue(job, *args)
8
- JobWrapper.enqueue job.name, *args, queue: job.queue_name
19
+ def enqueue(job) #:nodoc:
20
+ JobWrapper.enqueue job.serialize, queue: job.queue_name
9
21
  end
10
22
 
11
- def enqueue_at(job, timestamp, *args)
12
- raise NotImplementedError
23
+ def enqueue_at(job, timestamp) #:nodoc:
24
+ JobWrapper.enqueue job.serialize, queue: job.queue_name, run_at: Time.at(timestamp)
13
25
  end
14
26
  end
15
27
 
16
- class JobWrapper < Que::Job
17
- def run(job_name, *args)
18
- job_name.constantize.new.execute(*args)
28
+ class JobWrapper < Que::Job #:nodoc:
29
+ def run(job_data)
30
+ Base.execute job_data
19
31
  end
20
32
  end
21
33
  end
@@ -2,21 +2,50 @@ require 'queue_classic'
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
+ # == Queue Classic adapter for Active Job
6
+ #
7
+ # queue_classic provides a simple interface to a PostgreSQL-backed message
8
+ # queue. queue_classic specializes in concurrent locking and minimizing
9
+ # database load while providing a simple, intuitive developer experience.
10
+ # queue_classic assumes that you are already using PostgreSQL in your
11
+ # production environment and that adding another dependency (e.g. redis,
12
+ # beanstalkd, 0mq) is undesirable.
13
+ #
14
+ # Read more about Queue Classic {here}[https://github.com/ryandotsmith/queue_classic].
15
+ #
16
+ # To use Queue Classic set the queue_adapter config to +:queue_classic+.
17
+ #
18
+ # Rails.application.config.active_job.queue_adapter = :queue_classic
5
19
  class QueueClassicAdapter
6
20
  class << self
7
- def enqueue(job, *args)
8
- QC::Queue.new(job.queue_name).enqueue("#{JobWrapper.name}.perform", job.name, *args)
21
+ def enqueue(job) #:nodoc:
22
+ build_queue(job.queue_name).enqueue("#{JobWrapper.name}.perform", job.serialize)
9
23
  end
10
24
 
11
- def enqueue_at(job, timestamp, *args)
12
- raise NotImplementedError
25
+ def enqueue_at(job, timestamp) #:nodoc:
26
+ queue = build_queue(job.queue_name)
27
+ unless queue.respond_to?(:enqueue_at)
28
+ raise NotImplementedError, 'To be able to schedule jobs with Queue Classic ' \
29
+ 'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. '
30
+ 'You can implement this yourself or you can use the queue_classic-later gem.'
31
+ end
32
+ queue.enqueue_at(timestamp, "#{JobWrapper.name}.perform", job.serialize)
33
+ end
34
+
35
+ # Builds a <tt>QC::Queue</tt> object to schedule jobs on.
36
+ #
37
+ # If you have a custom <tt>QC::Queue</tt> subclass you'll need to suclass
38
+ # <tt>ActiveJob::QueueAdapters::QueueClassicAdapter</tt> and override the
39
+ # <tt>build_queue</tt> method.
40
+ def build_queue(queue_name)
41
+ QC::Queue.new(queue_name)
13
42
  end
14
43
  end
15
44
 
16
- class JobWrapper
45
+ class JobWrapper #:nodoc:
17
46
  class << self
18
- def perform(job_name, *args)
19
- job_name.constantize.new.execute(*args)
47
+ def perform(job_data)
48
+ Base.execute job_data
20
49
  end
21
50
  end
22
51
  end