activejob 7.0.8 → 7.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +128 -150
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +2 -2
  5. data/lib/active_job/arguments.rb +14 -25
  6. data/lib/active_job/base.rb +1 -1
  7. data/lib/active_job/callbacks.rb +1 -4
  8. data/lib/active_job/configured_job.rb +4 -0
  9. data/lib/active_job/core.rb +26 -6
  10. data/lib/active_job/deprecator.rb +7 -0
  11. data/lib/active_job/enqueuing.rb +31 -1
  12. data/lib/active_job/exceptions.rb +42 -5
  13. data/lib/active_job/execution.rb +5 -1
  14. data/lib/active_job/gem_version.rb +4 -4
  15. data/lib/active_job/instrumentation.rb +18 -10
  16. data/lib/active_job/log_subscriber.rb +78 -8
  17. data/lib/active_job/queue_adapter.rb +13 -2
  18. data/lib/active_job/queue_adapters/async_adapter.rb +2 -2
  19. data/lib/active_job/queue_adapters/backburner_adapter.rb +7 -3
  20. data/lib/active_job/queue_adapters/delayed_job_adapter.rb +1 -1
  21. data/lib/active_job/queue_adapters/inline_adapter.rb +1 -1
  22. data/lib/active_job/queue_adapters/queue_classic_adapter.rb +4 -4
  23. data/lib/active_job/queue_adapters/resque_adapter.rb +1 -1
  24. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +42 -14
  25. data/lib/active_job/queue_adapters/sneakers_adapter.rb +1 -1
  26. data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +2 -2
  27. data/lib/active_job/queue_adapters/test_adapter.rb +3 -3
  28. data/lib/active_job/queue_adapters.rb +8 -7
  29. data/lib/active_job/queue_priority.rb +18 -1
  30. data/lib/active_job/railtie.rb +25 -6
  31. data/lib/active_job/serializers/big_decimal_serializer.rb +22 -0
  32. data/lib/active_job/serializers/duration_serializer.rb +4 -2
  33. data/lib/active_job/serializers.rb +7 -3
  34. data/lib/active_job/test_helper.rb +23 -3
  35. data/lib/active_job/version.rb +1 -1
  36. data/lib/active_job.rb +26 -4
  37. data/lib/rails/generators/job/USAGE +19 -0
  38. data/lib/rails/generators/job/job_generator.rb +6 -2
  39. data/lib/rails/generators/job/templates/job.rb.tt +1 -1
  40. metadata +12 -10
  41. data/lib/active_job/queue_adapters/que_adapter.rb +0 -61
@@ -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
@@ -25,6 +29,15 @@ module ActiveJob
25
29
  options = app.config.active_job
26
30
  options.queue_adapter ||= :async
27
31
 
32
+ config.after_initialize do
33
+ options.each do |k, v|
34
+ k = "#{k}="
35
+ if ActiveJob.respond_to?(k)
36
+ ActiveJob.send(k, v)
37
+ end
38
+ end
39
+ end
40
+
28
41
  ActiveSupport.on_load(:active_job) do
29
42
  # Configs used in other initializers
30
43
  options = options.except(
@@ -32,19 +45,19 @@ module ActiveJob
32
45
  :custom_serializers
33
46
  )
34
47
 
35
- options.each do |k, v|
48
+ options.each do |k, v|
36
49
  k = "#{k}="
37
- send(k, v) if respond_to? k
50
+ if ActiveJob.respond_to?(k)
51
+ ActiveJob.send(k, v)
52
+ elsif respond_to? k
53
+ send(k, v)
54
+ end
38
55
  end
39
56
  end
40
57
 
41
58
  ActiveSupport.on_load(:action_dispatch_integration_test) do
42
59
  include ActiveJob::TestHelper
43
60
  end
44
-
45
- ActiveSupport.on_load(:active_record) do
46
- self.destroy_association_async_job = ActiveRecord::DestroyAssociationAsyncJob
47
- end
48
61
  end
49
62
 
50
63
  initializer "active_job.set_reloader_hook" do |app|
@@ -70,5 +83,11 @@ module ActiveJob
70
83
  end
71
84
  end
72
85
  end
86
+
87
+ initializer "active_job.backtrace_cleaner" do
88
+ ActiveSupport.on_load(:active_job) do
89
+ LogSubscriber.backtrace_cleaner = ::Rails.backtrace_cleaner
90
+ end
91
+ end
73
92
  end
74
93
  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
@@ -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
@@ -354,6 +354,13 @@ module ActiveJob
354
354
  # assert_enqueued_with(at: Date.tomorrow.noon, queue: "my_queue")
355
355
  # end
356
356
  #
357
+ # For keyword arguments, specify them as a hash inside an array:
358
+ #
359
+ # def test_assert_enqueued_with_keyword_arguments
360
+ # MyJob.perform_later(arg1: 'value1', arg2: 'value2')
361
+ # assert_enqueued_with(job: MyJob, args: [{ arg1: 'value1', arg2: 'value2' }])
362
+ # end
363
+ #
357
364
  # The given arguments may also be specified as matcher procs that return a
358
365
  # boolean value indicating whether a job's attribute meets certain criteria.
359
366
  #
@@ -595,9 +602,14 @@ module ActiveJob
595
602
  #
596
603
  # If the +:at+ option is specified, then only run jobs enqueued to run
597
604
  # immediately or before the given time
605
+ #
606
+ # If an adapter other than the test adapter is in use, this method just yields.
607
+ # See queue_adapter_for_test for more information.
598
608
  def perform_enqueued_jobs(only: nil, except: nil, queue: nil, at: nil, &block)
599
609
  return flush_enqueued_jobs(only: only, except: except, queue: queue, at: at) unless block_given?
600
610
 
611
+ return _assert_nothing_raised_or_warn("perform_enqueued_jobs", &block) unless using_test_adapter?
612
+
601
613
  validate_option(only: only, except: except)
602
614
 
603
615
  old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
@@ -636,12 +648,16 @@ module ActiveJob
636
648
  end
637
649
 
638
650
  private
651
+ def using_test_adapter?
652
+ queue_adapter.is_a?(ActiveJob::QueueAdapters::TestAdapter)
653
+ end
654
+
639
655
  def clear_enqueued_jobs
640
- enqueued_jobs.clear
656
+ enqueued_jobs.clear if using_test_adapter?
641
657
  end
642
658
 
643
659
  def clear_performed_jobs
644
- performed_jobs.clear
660
+ performed_jobs.clear if using_test_adapter?
645
661
  end
646
662
 
647
663
  def jobs_with(jobs, only: nil, except: nil, queue: nil, at: nil)
@@ -694,6 +710,10 @@ module ActiveJob
694
710
 
695
711
  def prepare_args_for_assertion(args)
696
712
  args.dup.tap do |arguments|
713
+ if arguments[:queue].is_a?(Symbol)
714
+ arguments[:queue] = arguments[:queue].to_s
715
+ end
716
+
697
717
  if arguments[:at].acts_like?(:time)
698
718
  at_range = arguments[:at] - 1..arguments[:at] + 1
699
719
  arguments[:at] = ->(at) { at_range.cover?(at) }
@@ -710,7 +730,7 @@ module ActiveJob
710
730
 
711
731
  def instantiate_job(payload, skip_deserialize_arguments: false)
712
732
  job = payload[:job].deserialize(payload)
713
- job.scheduled_at = Time.at(payload[:at]) if payload.key?(:at)
733
+ job.scheduled_at = payload[:at] if payload.key?(:at)
714
734
  job.send(:deserialize_arguments_if_needed) unless skip_deserialize_arguments
715
735
  job
716
736
  end
@@ -3,7 +3,7 @@
3
3
  require_relative "gem_version"
4
4
 
5
5
  module ActiveJob
6
- # Returns the currently loaded version of Active Job as a <tt>Gem::Version</tt>.
6
+ # Returns the currently loaded version of Active Job as a +Gem::Version+.
7
7
  def self.version
8
8
  gem_version
9
9
  end
data/lib/active_job.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2014-2022 David Heinemeier Hansson
4
+ # Copyright (c) David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -26,16 +26,38 @@
26
26
  require "active_support"
27
27
  require "active_support/rails"
28
28
  require "active_job/version"
29
+ require "active_job/deprecator"
29
30
  require "global_id"
30
31
 
32
+ # :markup: markdown
33
+ # :include: activejob/README.md
31
34
  module ActiveJob
32
35
  extend ActiveSupport::Autoload
33
36
 
34
37
  autoload :Base
35
38
  autoload :QueueAdapters
36
- autoload :Serializers
37
- autoload :ConfiguredJob
39
+
40
+ eager_autoload do
41
+ autoload :Serializers
42
+ autoload :ConfiguredJob
43
+ end
44
+
38
45
  autoload :TestCase
39
46
  autoload :TestHelper
40
- autoload :QueryTags
47
+
48
+ ##
49
+ # :singleton-method:
50
+ # If false, \Rails will preserve the legacy serialization of BigDecimal job arguments as Strings.
51
+ # If true, \Rails will use the new BigDecimalSerializer to (de)serialize BigDecimal losslessly.
52
+ # Legacy serialization will be removed in \Rails 7.2, along with this config.
53
+ singleton_class.attr_accessor :use_big_decimal_serializer
54
+ self.use_big_decimal_serializer = false
55
+
56
+ ##
57
+ # :singleton-method:
58
+ #
59
+ # Specifies if the methods calling background job enqueue should be logged below
60
+ # their relevant enqueue log lines. Defaults to false.
61
+ singleton_class.attr_accessor :verbose_enqueue_logs
62
+ self.verbose_enqueue_logs = false
41
63
  end
@@ -0,0 +1,19 @@
1
+ Description:
2
+ Generates a new job. Pass the job name, either CamelCased or
3
+ under_scored, with or without the job postfix.
4
+
5
+ Examples:
6
+ `bin/rails generate job checkout`
7
+
8
+ Creates the following files:
9
+
10
+ Job: app/jobs/checkout_job.rb
11
+ Test: test/jobs/checkout_job_test.rb
12
+
13
+ `bin/rails generate job send_sms --queue=sms`
14
+
15
+ Creates a job and test with a custom sms queue.
16
+
17
+ `bin/rails generate job process_payment --parent=payment_job`
18
+
19
+ Creates a job and test with a `PaymentJob` parent class.
@@ -5,10 +5,10 @@ require "rails/generators/named_base"
5
5
  module Rails # :nodoc:
6
6
  module Generators # :nodoc:
7
7
  class JobGenerator < Rails::Generators::NamedBase # :nodoc:
8
- desc "This generator creates an active job file at app/jobs"
9
-
10
8
  class_option :queue, type: :string, default: "default", desc: "The queue name for the generated job"
11
9
 
10
+ class_option :parent, type: :string, default: "ApplicationJob", desc: "The parent class for the generated job"
11
+
12
12
  check_class_collision suffix: "Job"
13
13
 
14
14
  hook_for :test_framework
@@ -28,6 +28,10 @@ module Rails # :nodoc:
28
28
  end
29
29
 
30
30
  private
31
+ def parent_class_name
32
+ options[:parent]
33
+ end
34
+
31
35
  def file_name
32
36
  @_file_name ||= super.sub(/_job\z/i, "")
33
37
  end
@@ -1,5 +1,5 @@
1
1
  <% module_namespacing do -%>
2
- class <%= class_name %>Job < ApplicationJob
2
+ class <%= class_name %>Job < <%= parent_class_name.classify %>
3
3
  queue_as :<%= options[:queue] %>
4
4
 
5
5
  def perform(*args)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activejob
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.8
4
+ version: 7.1.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-09 00:00:00.000000000 Z
11
+ date: 2023-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 7.0.8
19
+ version: 7.1.0.rc1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 7.0.8
26
+ version: 7.1.0.rc1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: globalid
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,6 +53,7 @@ files:
53
53
  - lib/active_job/callbacks.rb
54
54
  - lib/active_job/configured_job.rb
55
55
  - lib/active_job/core.rb
56
+ - lib/active_job/deprecator.rb
56
57
  - lib/active_job/enqueuing.rb
57
58
  - lib/active_job/exceptions.rb
58
59
  - lib/active_job/execution.rb
@@ -66,7 +67,6 @@ files:
66
67
  - lib/active_job/queue_adapters/backburner_adapter.rb
67
68
  - lib/active_job/queue_adapters/delayed_job_adapter.rb
68
69
  - lib/active_job/queue_adapters/inline_adapter.rb
69
- - lib/active_job/queue_adapters/que_adapter.rb
70
70
  - lib/active_job/queue_adapters/queue_classic_adapter.rb
71
71
  - lib/active_job/queue_adapters/resque_adapter.rb
72
72
  - lib/active_job/queue_adapters/sidekiq_adapter.rb
@@ -77,6 +77,7 @@ files:
77
77
  - lib/active_job/queue_priority.rb
78
78
  - lib/active_job/railtie.rb
79
79
  - lib/active_job/serializers.rb
80
+ - lib/active_job/serializers/big_decimal_serializer.rb
80
81
  - lib/active_job/serializers/date_serializer.rb
81
82
  - lib/active_job/serializers/date_time_serializer.rb
82
83
  - lib/active_job/serializers/duration_serializer.rb
@@ -92,6 +93,7 @@ files:
92
93
  - lib/active_job/timezones.rb
93
94
  - lib/active_job/translation.rb
94
95
  - lib/active_job/version.rb
96
+ - lib/rails/generators/job/USAGE
95
97
  - lib/rails/generators/job/job_generator.rb
96
98
  - lib/rails/generators/job/templates/application_job.rb.tt
97
99
  - lib/rails/generators/job/templates/job.rb.tt
@@ -100,10 +102,10 @@ licenses:
100
102
  - MIT
101
103
  metadata:
102
104
  bug_tracker_uri: https://github.com/rails/rails/issues
103
- changelog_uri: https://github.com/rails/rails/blob/v7.0.8/activejob/CHANGELOG.md
104
- documentation_uri: https://api.rubyonrails.org/v7.0.8/
105
+ changelog_uri: https://github.com/rails/rails/blob/v7.1.0.rc1/activejob/CHANGELOG.md
106
+ documentation_uri: https://api.rubyonrails.org/v7.1.0.rc1/
105
107
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
106
- source_code_uri: https://github.com/rails/rails/tree/v7.0.8/activejob
108
+ source_code_uri: https://github.com/rails/rails/tree/v7.1.0.rc1/activejob
107
109
  rubygems_mfa_required: 'true'
108
110
  post_install_message:
109
111
  rdoc_options: []
@@ -116,9 +118,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
118
  version: 2.7.0
117
119
  required_rubygems_version: !ruby/object:Gem::Requirement
118
120
  requirements:
119
- - - ">="
121
+ - - ">"
120
122
  - !ruby/object:Gem::Version
121
- version: '0'
123
+ version: 1.3.1
122
124
  requirements: []
123
125
  rubygems_version: 3.4.18
124
126
  signing_key:
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "que"
4
-
5
- module ActiveJob
6
- module QueueAdapters
7
- # == Que adapter for Active Job
8
- #
9
- # Que is a high-performance alternative to DelayedJob or QueueClassic that
10
- # improves the reliability of your application by protecting your jobs with
11
- # the same ACID guarantees as the rest of your data. Que is a queue for
12
- # Ruby and PostgreSQL that manages jobs using advisory locks.
13
- #
14
- # Read more about Que {here}[https://github.com/chanks/que].
15
- #
16
- # To use Que set the queue_adapter config to +:que+.
17
- #
18
- # Rails.application.config.active_job.queue_adapter = :que
19
- class QueAdapter
20
- def enqueue(job) # :nodoc:
21
- job_options = { priority: job.priority, queue: job.queue_name }
22
- que_job = nil
23
-
24
- if require_job_options_kwarg?
25
- que_job = JobWrapper.enqueue job.serialize, job_options: job_options
26
- else
27
- que_job = JobWrapper.enqueue job.serialize, **job_options
28
- end
29
-
30
- job.provider_job_id = que_job.attrs["job_id"]
31
- que_job
32
- end
33
-
34
- def enqueue_at(job, timestamp) # :nodoc:
35
- job_options = { priority: job.priority, queue: job.queue_name, run_at: Time.at(timestamp) }
36
- que_job = nil
37
-
38
- if require_job_options_kwarg?
39
- que_job = JobWrapper.enqueue job.serialize, job_options: job_options
40
- else
41
- que_job = JobWrapper.enqueue job.serialize, **job_options
42
- end
43
-
44
- job.provider_job_id = que_job.attrs["job_id"]
45
- que_job
46
- end
47
-
48
- private
49
- def require_job_options_kwarg?
50
- @require_job_options_kwarg ||=
51
- JobWrapper.method(:enqueue).parameters.any? { |ptype, pname| ptype == :key && pname == :job_options }
52
- end
53
-
54
- class JobWrapper < Que::Job # :nodoc:
55
- def run(job_data)
56
- Base.execute job_data
57
- end
58
- end
59
- end
60
- end
61
- end