activejob 7.0.8.7 → 7.2.2.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -229
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +2 -2
  5. data/lib/active_job/arguments.rb +18 -32
  6. data/lib/active_job/base.rb +1 -1
  7. data/lib/active_job/callbacks.rb +3 -8
  8. data/lib/active_job/configured_job.rb +4 -0
  9. data/lib/active_job/core.rb +11 -6
  10. data/lib/active_job/deprecator.rb +7 -0
  11. data/lib/active_job/enqueue_after_transaction_commit.rb +28 -0
  12. data/lib/active_job/enqueuing.rb +71 -12
  13. data/lib/active_job/exceptions.rb +44 -7
  14. data/lib/active_job/execution.rb +5 -2
  15. data/lib/active_job/gem_version.rb +4 -4
  16. data/lib/active_job/instrumentation.rb +18 -10
  17. data/lib/active_job/log_subscriber.rb +80 -8
  18. data/lib/active_job/logging.rb +16 -2
  19. data/lib/active_job/queue_adapter.rb +18 -6
  20. data/lib/active_job/queue_adapters/abstract_adapter.rb +27 -0
  21. data/lib/active_job/queue_adapters/async_adapter.rb +3 -3
  22. data/lib/active_job/queue_adapters/backburner_adapter.rb +8 -4
  23. data/lib/active_job/queue_adapters/delayed_job_adapter.rb +10 -2
  24. data/lib/active_job/queue_adapters/inline_adapter.rb +6 -2
  25. data/lib/active_job/queue_adapters/queue_classic_adapter.rb +13 -5
  26. data/lib/active_job/queue_adapters/resque_adapter.rb +2 -2
  27. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +43 -15
  28. data/lib/active_job/queue_adapters/sneakers_adapter.rb +2 -2
  29. data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +4 -4
  30. data/lib/active_job/queue_adapters/test_adapter.rb +13 -5
  31. data/lib/active_job/queue_adapters.rb +9 -7
  32. data/lib/active_job/queue_priority.rb +18 -1
  33. data/lib/active_job/railtie.rb +38 -7
  34. data/lib/active_job/serializers/big_decimal_serializer.rb +22 -0
  35. data/lib/active_job/serializers/duration_serializer.rb +4 -2
  36. data/lib/active_job/serializers/object_serializer.rb +2 -0
  37. data/lib/active_job/serializers/time_with_zone_serializer.rb +11 -2
  38. data/lib/active_job/serializers.rb +7 -3
  39. data/lib/active_job/test_helper.rb +60 -19
  40. data/lib/active_job/version.rb +1 -1
  41. data/lib/active_job.rb +34 -4
  42. data/lib/rails/generators/job/USAGE +19 -0
  43. data/lib/rails/generators/job/job_generator.rb +6 -2
  44. data/lib/rails/generators/job/templates/job.rb.tt +1 -1
  45. metadata +12 -8
  46. data/lib/active_job/queue_adapters/que_adapter.rb +0 -61
@@ -5,7 +5,7 @@ require "active_support/core_ext/string/inflections"
5
5
 
6
6
  module ActiveJob
7
7
  module QueueAdapters
8
- # == Delayed Job adapter for Active Job
8
+ # = Delayed Job adapter for Active Job
9
9
  #
10
10
  # Delayed::Job (or DJ) encapsulates the common pattern of asynchronously
11
11
  # executing longer tasks in the background. Although DJ can have many
@@ -15,7 +15,15 @@ module ActiveJob
15
15
  # To use Delayed Job, set the queue_adapter config to +:delayed_job+.
16
16
  #
17
17
  # Rails.application.config.active_job.queue_adapter = :delayed_job
18
- class DelayedJobAdapter
18
+ class DelayedJobAdapter < AbstractAdapter
19
+ def initialize(enqueue_after_transaction_commit: false)
20
+ @enqueue_after_transaction_commit = enqueue_after_transaction_commit
21
+ end
22
+
23
+ def enqueue_after_transaction_commit? # :nodoc:
24
+ @enqueue_after_transaction_commit
25
+ end
26
+
19
27
  def enqueue(job) # :nodoc:
20
28
  delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, priority: job.priority)
21
29
  job.provider_job_id = delayed_job.id
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
- # == Active Job Inline adapter
5
+ # = Active Job Inline adapter
6
6
  #
7
7
  # When enqueuing jobs with the Inline adapter the job will be executed
8
8
  # immediately.
@@ -10,7 +10,11 @@ module ActiveJob
10
10
  # To use the Inline set the queue_adapter config to +:inline+.
11
11
  #
12
12
  # Rails.application.config.active_job.queue_adapter = :inline
13
- class InlineAdapter
13
+ class InlineAdapter < AbstractAdapter
14
+ def enqueue_after_transaction_commit? # :nodoc:
15
+ false
16
+ end
17
+
14
18
  def enqueue(job) # :nodoc:
15
19
  Base.execute(job.serialize)
16
20
  end
@@ -4,7 +4,7 @@ require "queue_classic"
4
4
 
5
5
  module ActiveJob
6
6
  module QueueAdapters
7
- # == queue_classic adapter for Active Job
7
+ # = queue_classic adapter for Active Job
8
8
  #
9
9
  # queue_classic provides a simple interface to a PostgreSQL-backed message
10
10
  # queue. queue_classic specializes in concurrent locking and minimizing
@@ -18,7 +18,15 @@ module ActiveJob
18
18
  # To use queue_classic set the queue_adapter config to +:queue_classic+.
19
19
  #
20
20
  # Rails.application.config.active_job.queue_adapter = :queue_classic
21
- class QueueClassicAdapter
21
+ class QueueClassicAdapter < AbstractAdapter
22
+ def initialize(enqueue_after_transaction_commit: false)
23
+ @enqueue_after_transaction_commit = enqueue_after_transaction_commit
24
+ end
25
+
26
+ def enqueue_after_transaction_commit? # :nodoc:
27
+ @enqueue_after_transaction_commit
28
+ end
29
+
22
30
  def enqueue(job) # :nodoc:
23
31
  qc_job = build_queue(job.queue_name).enqueue("#{JobWrapper.name}.perform", job.serialize)
24
32
  job.provider_job_id = qc_job["id"] if qc_job.is_a?(Hash)
@@ -37,10 +45,10 @@ module ActiveJob
37
45
  qc_job
38
46
  end
39
47
 
40
- # Builds a <tt>QC::Queue</tt> object to schedule jobs on.
48
+ # Builds a +QC::Queue+ object to schedule jobs on.
41
49
  #
42
- # If you have a custom <tt>QC::Queue</tt> subclass you'll need to subclass
43
- # <tt>ActiveJob::QueueAdapters::QueueClassicAdapter</tt> and override the
50
+ # If you have a custom +QC::Queue+ subclass you'll need to subclass
51
+ # +ActiveJob::QueueAdapters::QueueClassicAdapter+ and override the
44
52
  # <tt>build_queue</tt> method.
45
53
  def build_queue(queue_name)
46
54
  QC::Queue.new(queue_name)
@@ -16,7 +16,7 @@ end
16
16
 
17
17
  module ActiveJob
18
18
  module QueueAdapters
19
- # == Resque adapter for Active Job
19
+ # = Resque adapter for Active Job
20
20
  #
21
21
  # Resque (pronounced like "rescue") is a Redis-backed library for creating
22
22
  # background jobs, placing those jobs on multiple queues, and processing
@@ -27,7 +27,7 @@ module ActiveJob
27
27
  # To use Resque set the queue_adapter config to +:resque+.
28
28
  #
29
29
  # Rails.application.config.active_job.queue_adapter = :resque
30
- class ResqueAdapter
30
+ class ResqueAdapter < AbstractAdapter
31
31
  def enqueue(job) # :nodoc:
32
32
  JobWrapper.instance_variable_set(:@queue, job.queue_name)
33
33
  Resque.enqueue_to job.queue_name, JobWrapper, job.serialize
@@ -1,14 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ gem "sidekiq", ">= 4.1.0"
3
4
  require "sidekiq"
4
5
 
5
6
  module ActiveJob
6
7
  module QueueAdapters
7
- # == Sidekiq adapter for Active Job
8
+ # = Sidekiq adapter for Active Job
8
9
  #
9
10
  # Simple, efficient background processing for Ruby. Sidekiq uses threads to
10
11
  # handle many jobs at the same time in the same process. It does not
11
- # require Rails but will integrate tightly with it to make background
12
+ # require \Rails but will integrate tightly with it to make background
12
13
  # processing dead simple.
13
14
  #
14
15
  # Read more about Sidekiq {here}[http://sidekiq.org].
@@ -16,23 +17,50 @@ module ActiveJob
16
17
  # To use Sidekiq set the queue_adapter config to +:sidekiq+.
17
18
  #
18
19
  # Rails.application.config.active_job.queue_adapter = :sidekiq
19
- class SidekiqAdapter
20
+ class SidekiqAdapter < AbstractAdapter
20
21
  def enqueue(job) # :nodoc:
21
- # Sidekiq::Client does not support symbols as keys
22
- job.provider_job_id = Sidekiq::Client.push \
23
- "class" => JobWrapper,
24
- "wrapped" => job.class,
25
- "queue" => job.queue_name,
26
- "args" => [ job.serialize ]
22
+ job.provider_job_id = JobWrapper.set(
23
+ wrapped: job.class,
24
+ queue: job.queue_name
25
+ ).perform_async(job.serialize)
27
26
  end
28
27
 
29
28
  def enqueue_at(job, timestamp) # :nodoc:
30
- job.provider_job_id = Sidekiq::Client.push \
31
- "class" => JobWrapper,
32
- "wrapped" => job.class,
33
- "queue" => job.queue_name,
34
- "args" => [ job.serialize ],
35
- "at" => timestamp
29
+ job.provider_job_id = JobWrapper.set(
30
+ wrapped: job.class,
31
+ queue: job.queue_name,
32
+ ).perform_at(timestamp, job.serialize)
33
+ end
34
+
35
+ def enqueue_all(jobs) # :nodoc:
36
+ enqueued_count = 0
37
+ jobs.group_by(&:class).each do |job_class, same_class_jobs|
38
+ same_class_jobs.group_by(&:queue_name).each do |queue, same_class_and_queue_jobs|
39
+ immediate_jobs, scheduled_jobs = same_class_and_queue_jobs.partition { |job| job.scheduled_at.nil? }
40
+
41
+ if immediate_jobs.any?
42
+ jids = Sidekiq::Client.push_bulk(
43
+ "class" => JobWrapper,
44
+ "wrapped" => job_class,
45
+ "queue" => queue,
46
+ "args" => immediate_jobs.map { |job| [job.serialize] },
47
+ )
48
+ enqueued_count += jids.compact.size
49
+ end
50
+
51
+ if scheduled_jobs.any?
52
+ jids = Sidekiq::Client.push_bulk(
53
+ "class" => JobWrapper,
54
+ "wrapped" => job_class,
55
+ "queue" => queue,
56
+ "args" => scheduled_jobs.map { |job| [job.serialize] },
57
+ "at" => scheduled_jobs.map { |job| job.scheduled_at&.to_f }
58
+ )
59
+ enqueued_count += jids.compact.size
60
+ end
61
+ end
62
+ end
63
+ enqueued_count
36
64
  end
37
65
 
38
66
  class JobWrapper # :nodoc:
@@ -5,7 +5,7 @@ require "monitor"
5
5
 
6
6
  module ActiveJob
7
7
  module QueueAdapters
8
- # == Sneakers adapter for Active Job
8
+ # = Sneakers adapter for Active Job
9
9
  #
10
10
  # A high-performance RabbitMQ background processing framework for Ruby.
11
11
  # Sneakers is being used in production for both I/O and CPU intensive
@@ -17,7 +17,7 @@ module ActiveJob
17
17
  # To use Sneakers set the queue_adapter config to +:sneakers+.
18
18
  #
19
19
  # Rails.application.config.active_job.queue_adapter = :sneakers
20
- class SneakersAdapter
20
+ class SneakersAdapter < AbstractAdapter
21
21
  def initialize
22
22
  @monitor = Monitor.new
23
23
  end
@@ -4,20 +4,20 @@ require "sucker_punch"
4
4
 
5
5
  module ActiveJob
6
6
  module QueueAdapters
7
- # == Sucker Punch adapter for Active Job
7
+ # = Sucker Punch adapter for Active Job
8
8
  #
9
9
  # Sucker Punch is a single-process Ruby asynchronous processing library.
10
10
  # This reduces the cost of hosting on a service like Heroku along
11
11
  # with the memory footprint of having to maintain additional jobs if
12
12
  # hosting on a dedicated server. All queues can run within a
13
- # single application (e.g. Rails, Sinatra, etc.) process.
13
+ # single application (e.g. \Rails, Sinatra, etc.) process.
14
14
  #
15
15
  # Read more about Sucker Punch {here}[https://github.com/brandonhilkert/sucker_punch].
16
16
  #
17
17
  # To use Sucker Punch set the queue_adapter config to +:sucker_punch+.
18
18
  #
19
19
  # Rails.application.config.active_job.queue_adapter = :sucker_punch
20
- class SuckerPunchAdapter
20
+ class SuckerPunchAdapter < AbstractAdapter
21
21
  def enqueue(job) # :nodoc:
22
22
  if JobWrapper.respond_to?(:perform_async)
23
23
  # sucker_punch 2.0 API
@@ -33,7 +33,7 @@ module ActiveJob
33
33
  delay = timestamp - Time.current.to_f
34
34
  JobWrapper.perform_in delay, job.serialize
35
35
  else
36
- raise NotImplementedError, "sucker_punch 1.0 does not support `enqueued_at`. Please upgrade to version ~> 2.0.0 to enable this behavior."
36
+ raise NotImplementedError, "sucker_punch 1.0 does not support `enqueue_at`. Please upgrade to version ~> 2.0.0 to enable this behavior."
37
37
  end
38
38
  end
39
39
 
@@ -2,19 +2,27 @@
2
2
 
3
3
  module ActiveJob
4
4
  module QueueAdapters
5
- # == Test adapter for Active Job
5
+ # = Test adapter for Active Job
6
6
  #
7
7
  # The test adapter should be used only in testing. Along with
8
8
  # ActiveJob::TestCase and ActiveJob::TestHelper
9
- # it makes a great tool to test your Rails application.
9
+ # it makes a great tool to test your \Rails application.
10
10
  #
11
11
  # To use the test adapter set +queue_adapter+ config to +:test+.
12
12
  #
13
13
  # Rails.application.config.active_job.queue_adapter = :test
14
- class TestAdapter
15
- attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter, :reject, :queue, :at)
14
+ class TestAdapter < AbstractAdapter
15
+ attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter, :reject, :queue, :at, :enqueue_after_transaction_commit)
16
16
  attr_writer(:enqueued_jobs, :performed_jobs)
17
17
 
18
+ def initialize(enqueue_after_transaction_commit: true)
19
+ @enqueue_after_transaction_commit = enqueue_after_transaction_commit
20
+ end
21
+
22
+ def enqueue_after_transaction_commit? # :nodoc:
23
+ @enqueue_after_transaction_commit
24
+ end
25
+
18
26
  # Provides a store of all the enqueued jobs with the TestAdapter so you can check them.
19
27
  def enqueued_jobs
20
28
  @enqueued_jobs ||= []
@@ -59,7 +67,7 @@ module ActiveJob
59
67
  end
60
68
 
61
69
  def filtered_time?(job)
62
- job.scheduled_at > at.to_f if at && job.scheduled_at
70
+ job.scheduled_at > at if at && job.scheduled_at
63
71
  end
64
72
 
65
73
  def filtered_queue?(job)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveJob
4
- # == Active Job adapters
4
+ # = Active Job adapters
5
5
  #
6
6
  # Active Job has adapters for the following queuing backends:
7
7
  #
@@ -13,10 +13,14 @@ module ActiveJob
13
13
  # * {Sidekiq}[https://sidekiq.org]
14
14
  # * {Sneakers}[https://github.com/jondot/sneakers]
15
15
  # * {Sucker Punch}[https://github.com/brandonhilkert/sucker_punch]
16
- # * {Active Job Async Job}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/AsyncAdapter.html]
17
- # * {Active Job Inline}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html]
18
16
  # * Please Note: We are not accepting pull requests for new adapters. See the {README}[link:files/activejob/README_md.html] for more details.
19
17
  #
18
+ # For testing and development Active Job has three built-in adapters:
19
+ #
20
+ # * {Active Job Async}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/AsyncAdapter.html]
21
+ # * {Active Job Inline}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html]
22
+ # * {Active Job Test}[https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/TestAdapter.html]
23
+ #
20
24
  # === Backends Features
21
25
  #
22
26
  # | | Async | Queues | Delayed | Priorities | Timeout | Retries |
@@ -31,6 +35,7 @@ module ActiveJob
31
35
  # | Sucker Punch | Yes | Yes | Yes | No | No | No |
32
36
  # | Active Job Async | Yes | Yes | Yes | No | No | No |
33
37
  # | Active Job Inline | No | Yes | N/A | N/A | N/A | N/A |
38
+ # | Active Job Test | No | Yes | N/A | N/A | N/A | N/A |
34
39
  #
35
40
  # ==== Async
36
41
  #
@@ -106,13 +111,10 @@ module ActiveJob
106
111
  # N/A: The adapter does not run in a separate process, and therefore doesn't
107
112
  # support retries.
108
113
  #
109
- # === Async and Inline Queue Adapters
110
- #
111
- # Active Job has two built-in queue adapters intended for development and
112
- # testing: +:async+ and +:inline+.
113
114
  module QueueAdapters
114
115
  extend ActiveSupport::Autoload
115
116
 
117
+ autoload :AbstractAdapter
116
118
  autoload :AsyncAdapter
117
119
  autoload :InlineAdapter
118
120
  autoload :BackburnerAdapter
@@ -18,7 +18,24 @@ module ActiveJob
18
18
  # end
19
19
  # end
20
20
  #
21
- # Specify either an argument or a block.
21
+ # Can be given a block that will evaluate in the context of the job
22
+ # so that a dynamic priority can be applied:
23
+ #
24
+ # class PublishToFeedJob < ApplicationJob
25
+ # queue_with_priority do
26
+ # post = self.arguments.first
27
+ #
28
+ # if post.paid?
29
+ # 10
30
+ # else
31
+ # 50
32
+ # end
33
+ # end
34
+ #
35
+ # def perform(post)
36
+ # post.to_feed!
37
+ # end
38
+ # end
22
39
  def queue_with_priority(priority = nil, &block)
23
40
  if block_given?
24
41
  self.priority = block
@@ -10,6 +10,10 @@ module ActiveJob
10
10
  config.active_job.custom_serializers = []
11
11
  config.active_job.log_query_tags_around_perform = true
12
12
 
13
+ initializer "active_job.deprecator", before: :load_environment_config do |app|
14
+ app.deprecators[:active_job] = ActiveJob.deprecator
15
+ end
16
+
13
17
  initializer "active_job.logger" do
14
18
  ActiveSupport.on_load(:active_job) { self.logger = ::Rails.logger }
15
19
  end
@@ -21,9 +25,30 @@ module ActiveJob
21
25
  end
22
26
  end
23
27
 
28
+ initializer "active_job.enqueue_after_transaction_commit" do |app|
29
+ ActiveSupport.on_load(:active_job) do
30
+ ActiveSupport.on_load(:active_record) do
31
+ ActiveJob::Base.include EnqueueAfterTransactionCommit
32
+
33
+ if app.config.active_job.key?(:enqueue_after_transaction_commit)
34
+ ActiveJob::Base.enqueue_after_transaction_commit = app.config.active_job.delete(:enqueue_after_transaction_commit)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
24
40
  initializer "active_job.set_configs" do |app|
25
41
  options = app.config.active_job
26
- options.queue_adapter ||= :async
42
+ options.queue_adapter ||= (Rails.env.test? ? :test : :async)
43
+
44
+ config.after_initialize do
45
+ options.each do |k, v|
46
+ k = "#{k}="
47
+ if ActiveJob.respond_to?(k)
48
+ ActiveJob.send(k, v)
49
+ end
50
+ end
51
+ end
27
52
 
28
53
  ActiveSupport.on_load(:active_job) do
29
54
  # Configs used in other initializers
@@ -32,19 +57,19 @@ module ActiveJob
32
57
  :custom_serializers
33
58
  )
34
59
 
35
- options.each do |k, v|
60
+ options.each do |k, v|
36
61
  k = "#{k}="
37
- send(k, v) if respond_to? k
62
+ if ActiveJob.respond_to?(k)
63
+ ActiveJob.send(k, v)
64
+ elsif respond_to? k
65
+ send(k, v)
66
+ end
38
67
  end
39
68
  end
40
69
 
41
70
  ActiveSupport.on_load(:action_dispatch_integration_test) do
42
71
  include ActiveJob::TestHelper
43
72
  end
44
-
45
- ActiveSupport.on_load(:active_record) do
46
- self.destroy_association_async_job = ActiveRecord::DestroyAssociationAsyncJob
47
- end
48
73
  end
49
74
 
50
75
  initializer "active_job.set_reloader_hook" do |app|
@@ -70,5 +95,11 @@ module ActiveJob
70
95
  end
71
96
  end
72
97
  end
98
+
99
+ initializer "active_job.backtrace_cleaner" do
100
+ ActiveSupport.on_load(:active_job) do
101
+ LogSubscriber.backtrace_cleaner = ::Rails.backtrace_cleaner
102
+ end
103
+ end
73
104
  end
74
105
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+
5
+ module ActiveJob
6
+ module Serializers
7
+ class BigDecimalSerializer < ObjectSerializer # :nodoc:
8
+ def serialize(big_decimal)
9
+ super("value" => big_decimal.to_s)
10
+ end
11
+
12
+ def deserialize(hash)
13
+ BigDecimal(hash["value"])
14
+ end
15
+
16
+ private
17
+ def klass
18
+ BigDecimal
19
+ end
20
+ end
21
+ end
22
+ end
@@ -4,14 +4,16 @@ module ActiveJob
4
4
  module Serializers
5
5
  class DurationSerializer < ObjectSerializer # :nodoc:
6
6
  def serialize(duration)
7
+ # Ideally duration.parts would be wrapped in an array before passing to Arguments.serialize,
8
+ # but we continue passing the bare hash for backwards compatibility:
7
9
  super("value" => duration.value, "parts" => Arguments.serialize(duration.parts))
8
10
  end
9
11
 
10
12
  def deserialize(hash)
11
13
  value = hash["value"]
12
14
  parts = Arguments.deserialize(hash["parts"])
13
-
14
- klass.new(value, parts)
15
+ # `parts` is originally a hash, but will have been flattened to an array by Arguments.serialize
16
+ klass.new(value, parts.to_h)
15
17
  end
16
18
 
17
19
  private
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "singleton"
4
+
3
5
  module ActiveJob
4
6
  module Serializers
5
7
  # Base class for serializing and deserializing custom objects.
@@ -2,9 +2,18 @@
2
2
 
3
3
  module ActiveJob
4
4
  module Serializers
5
- class TimeWithZoneSerializer < TimeObjectSerializer # :nodoc:
5
+ class TimeWithZoneSerializer < ObjectSerializer # :nodoc:
6
+ NANO_PRECISION = 9
7
+
8
+ def serialize(time_with_zone)
9
+ super(
10
+ "value" => time_with_zone.iso8601(NANO_PRECISION),
11
+ "time_zone" => time_with_zone.time_zone.tzinfo.name
12
+ )
13
+ end
14
+
6
15
  def deserialize(hash)
7
- Time.iso8601(hash["value"]).in_time_zone
16
+ Time.iso8601(hash["value"]).in_time_zone(hash["time_zone"] || Time.zone)
8
17
  end
9
18
 
10
19
  private
@@ -3,7 +3,9 @@
3
3
  require "set"
4
4
 
5
5
  module ActiveJob
6
- # The <tt>ActiveJob::Serializers</tt> module is used to store a list of known serializers
6
+ # = Active Job \Serializers
7
+ #
8
+ # The +ActiveJob::Serializers+ module is used to store a list of known serializers
7
9
  # and to add new ones. It also has helpers to serialize/deserialize objects.
8
10
  module Serializers # :nodoc:
9
11
  extend ActiveSupport::Autoload
@@ -18,6 +20,7 @@ module ActiveJob
18
20
  autoload :TimeSerializer
19
21
  autoload :ModuleSerializer
20
22
  autoload :RangeSerializer
23
+ autoload :BigDecimalSerializer
21
24
 
22
25
  mattr_accessor :_additional_serializers
23
26
  self._additional_serializers = Set.new
@@ -25,7 +28,7 @@ module ActiveJob
25
28
  class << self
26
29
  # Returns serialized representative of the passed object.
27
30
  # Will look up through all known serializers.
28
- # Raises <tt>ActiveJob::SerializationError</tt> if it can't find a proper serializer.
31
+ # Raises ActiveJob::SerializationError if it can't find a proper serializer.
29
32
  def serialize(argument)
30
33
  serializer = serializers.detect { |s| s.serialize?(argument) }
31
34
  raise SerializationError.new("Unsupported argument type: #{argument.class.name}") unless serializer
@@ -63,6 +66,7 @@ module ActiveJob
63
66
  TimeWithZoneSerializer,
64
67
  TimeSerializer,
65
68
  ModuleSerializer,
66
- RangeSerializer
69
+ RangeSerializer,
70
+ BigDecimalSerializer
67
71
  end
68
72
  end