good_job 2.8.0 → 2.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae78ac0322802107488f4a8b55963665cf9b3f173eb05174382bf05afdcef5a6
4
- data.tar.gz: 2f41dd00281bcf2d0a2c29f6124de36964dcc730436f1cbd2f4c740c873263ed
3
+ metadata.gz: 43a641edf5b6ff33dc8752874c6b317ad96bfd74ed4cbcb3a9bbeee7ff9c14cf
4
+ data.tar.gz: bfcf81a0d6c2d7bef01c3abdad9222fcc92cc8a5fd0ead3059fe5b9afd96aefa
5
5
  SHA512:
6
- metadata.gz: 0ec2d40fdd87f293f8372e27040c7b14f8668645f50bc968ce91ec758202a400bb7c4a9ecb2e31a5827d59717dc3069840d5402981e1dc9f98c113120e259258
7
- data.tar.gz: 0dd784cee33ab996ad332d1bfc371c357ffe3fb9727629096cff7189cc391195c109400240569444221a2ebf3340e2ab0d2d1c7bbd2830ee1c5b2ada9117d995
6
+ metadata.gz: ea801613572d4ccdce2af524303220eed9f50532ce80160c8fd9063bb994f0be725cf806d84aad8ea2bf5028f593a79fa13b5d1f7e796ece29eee70d42df9fa8
7
+ data.tar.gz: 9344d31ec8ffacdaa531a7e8bb7292270b151ad440d9dd95cd7ebfbe4106ca6b276ec3cff671df2ad97c9aee50892d453b584f948a7fc5e1bf7710fd935b2d40
data/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  # Changelog
2
2
 
3
+ ## [v2.9.2](https://github.com/bensheldon/good_job/tree/v2.9.2) (2022-01-19)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.9.1...v2.9.2)
6
+
7
+ **Fixed bugs:**
8
+
9
+ - Error on GJ admin UI search form [\#487](https://github.com/bensheldon/good_job/issues/487)
10
+ - Use `websearch_to_tsquery` or \(`plainto_tsquery` for Postgres \< v11\) for Dashboard search filter [\#488](https://github.com/bensheldon/good_job/pull/488) ([bensheldon](https://github.com/bensheldon))
11
+
12
+ **Merged pull requests:**
13
+
14
+ - Update README to illustrate using named arguments for the unique key. [\#486](https://github.com/bensheldon/good_job/pull/486) ([phallstrom](https://github.com/phallstrom))
15
+ - Add details about exactly where to require the engine. [\#485](https://github.com/bensheldon/good_job/pull/485) ([phallstrom](https://github.com/phallstrom))
16
+ - $ symbol gets copied when clicking on the copy button [\#484](https://github.com/bensheldon/good_job/pull/484) ([zeevy](https://github.com/zeevy))
17
+
18
+ ## [v2.9.1](https://github.com/bensheldon/good_job/tree/v2.9.1) (2022-01-13)
19
+
20
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.9.0...v2.9.1)
21
+
22
+ **Fixed bugs:**
23
+
24
+ - Start async adapters once `ActiveRecord` and `ActiveJob` have loaded, potentially before `Rails.application.initialized?` [\#483](https://github.com/bensheldon/good_job/pull/483) ([bensheldon](https://github.com/bensheldon))
25
+
26
+ **Closed issues:**
27
+
28
+ - Graceful fallback to polling when LISTEN/NOTIFY isn't available [\#482](https://github.com/bensheldon/good_job/issues/482)
29
+ - Long running locks on latest good job [\#480](https://github.com/bensheldon/good_job/issues/480)
30
+
31
+ ## [v2.9.0](https://github.com/bensheldon/good_job/tree/v2.9.0) (2022-01-09)
32
+
33
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.8.1...v2.9.0)
34
+
35
+ **Implemented enhancements:**
36
+
37
+ - Add JRuby / JDBC support for LISTEN [\#479](https://github.com/bensheldon/good_job/pull/479) ([bensheldon](https://github.com/bensheldon))
38
+
39
+ **Merged pull requests:**
40
+
41
+ - Remove demo CleanupJob in favor of using built-in cleanup intervals [\#478](https://github.com/bensheldon/good_job/pull/478) ([bensheldon](https://github.com/bensheldon))
42
+
43
+ ## [v2.8.1](https://github.com/bensheldon/good_job/tree/v2.8.1) (2022-01-03)
44
+
45
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.8.0...v2.8.1)
46
+
47
+ **Implemented enhancements:**
48
+
49
+ - Add indexes to `good_jobs.finished_at` and have `GoodJob.cleanup_preserved_jobs` delete all executions for a given job [\#477](https://github.com/bensheldon/good_job/pull/477) ([bensheldon](https://github.com/bensheldon))
50
+
51
+ **Closed issues:**
52
+
53
+ - finished\_at should be indexed and clean up should clean up all of a job's executions [\#476](https://github.com/bensheldon/good_job/issues/476)
54
+
55
+ **Merged pull requests:**
56
+
57
+ - Update development Ruby \(2.7.5\) and Rails \(6.1.4.4\) versions [\#475](https://github.com/bensheldon/good_job/pull/475) ([bensheldon](https://github.com/bensheldon))
58
+ - Clean up server integration tests [\#474](https://github.com/bensheldon/good_job/pull/474) ([bensheldon](https://github.com/bensheldon))
59
+
3
60
  ## [v2.8.0](https://github.com/bensheldon/good_job/tree/v2.8.0) (2021-12-31)
4
61
 
5
62
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.7.4...v2.8.0)
data/README.md CHANGED
@@ -73,19 +73,19 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
73
73
  1. Install the gem:
74
74
 
75
75
  ```bash
76
- $ bundle install
76
+ bundle install
77
77
  ```
78
78
 
79
79
  1. Run the GoodJob install generator. This will generate a database migration to create a table for GoodJob's job records:
80
80
 
81
81
  ```bash
82
- $ bin/rails g good_job:install
82
+ bin/rails g good_job:install
83
83
  ```
84
84
 
85
85
  Run the migration:
86
86
 
87
87
  ```bash
88
- $ bin/rails db:migrate
88
+ bin/rails db:migrate
89
89
  ```
90
90
 
91
91
  Optional: If using Rails' multiple databases with the `migrations_paths` configuration option, use the `--database` option:
@@ -142,7 +142,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
142
142
  ## Compatibility
143
143
 
144
144
  - **Ruby on Rails:** 5.2+
145
- - **Ruby:** MRI 2.5+. JRuby 9.2.13+ (_JRuby's `activerecord-jdbcpostgresql-adapter` gem does not support Postgres LISTEN/NOTIFY)._
145
+ - **Ruby:** MRI 2.5+. JRuby 9.2.13+
146
146
  - **Postgres:** 9.6+
147
147
 
148
148
  ## Configuration
@@ -328,7 +328,7 @@ _🚧 GoodJob's dashboard is a work in progress. Please contribute ideas and cod
328
328
 
329
329
  GoodJob includes a Dashboard as a mountable `Rails::Engine`.
330
330
 
331
- 1. Explicitly require the Engine code at the top of your `config/application.rb` file, immediately after Rails is required. This is necessary because the mountable engine is an optional feature of GoodJob.
331
+ 1. Explicitly require the Engine code at the top of your `config/application.rb` file, immediately after Rails is required and before Bundler requires the Rails' groups. This is necessary because the mountable engine is an optional feature of GoodJob.
332
332
 
333
333
  ```ruby
334
334
  # config/application.rb
@@ -339,6 +339,8 @@ GoodJob includes a Dashboard as a mountable `Rails::Engine`.
339
339
  # ...
340
340
  ```
341
341
 
342
+ Note: If you find the dashboard fails to reload due to a routing error and uninitialized constant `GoodJob::ExecutionsController`, this is likely because you are not requiring the engine early enough.
343
+
342
344
  1. Mount the engine in your `config/routes.rb` file. The following will mount it at `http://example.com/good_job`.
343
345
 
344
346
  ```ruby
@@ -399,6 +401,9 @@ class MyJob < ApplicationJob
399
401
  # Can be String or Lambda/Proc that is invoked in the context of the job.
400
402
  # Note: Arguments passed to #perform_later must be accessed through `arguments` method.
401
403
  key: -> { "Unique-#{arguments.first}" } # MyJob.perform_later("Alice") => "Unique-Alice"
404
+
405
+ # If the method uses named parameters, they can be accessed like so:
406
+ # key: -> { "Unique-#{arguments.first['name']}" } # MyJob.perform_later(name: "Alice")
402
407
  )
403
408
 
404
409
  def perform(first_name)
@@ -32,5 +32,7 @@ class CreateGoodJobs < ActiveRecord::Migration<%= migration_version %>
32
32
  add_index :good_jobs, :concurrency_key, where: "(finished_at IS NULL)", name: :index_good_jobs_on_concurrency_key_when_unfinished
33
33
  add_index :good_jobs, [:cron_key, :created_at], name: :index_good_jobs_on_cron_key_and_created_at
34
34
  add_index :good_jobs, [:cron_key, :cron_at], name: :index_good_jobs_on_cron_key_and_cron_at, unique: true
35
+ add_index :good_jobs, [:active_job_id], name: :index_good_jobs_on_active_job_id
36
+ add_index :good_jobs, [:finished_at], where: "retried_good_job_id IS NULL AND finished_at IS NOT NULL", name: :index_good_jobs_jobs_on_finished_at
35
37
  end
36
38
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ class IndexGoodJobJobsOnFinishedAt < ActiveRecord::Migration<%= migration_version %>
3
+ disable_ddl_transaction!
4
+
5
+ def change
6
+ reversible do |dir|
7
+ dir.up do
8
+ # Ensure this incremental update migration is idempotent
9
+ # with monolithic install migration.
10
+ return if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id)
11
+ end
12
+ end
13
+
14
+ add_index :good_jobs,
15
+ [:active_job_id],
16
+ name: :index_good_jobs_on_active_job_id,
17
+ algorithm: :concurrently
18
+
19
+ add_index :good_jobs,
20
+ [:finished_at],
21
+ where: "retried_good_job_id IS NULL AND finished_at IS NOT NULL",
22
+ name: :index_good_jobs_jobs_on_finished_at,
23
+ algorithm: :concurrently
24
+ end
25
+ end
@@ -19,7 +19,7 @@ module GoodJob
19
19
  self.primary_key = 'active_job_id'
20
20
  self.advisory_lockable_column = 'active_job_id'
21
21
 
22
- has_many :executions, -> { order(created_at: :asc) }, class_name: 'GoodJob::Execution', foreign_key: 'active_job_id'
22
+ has_many :executions, -> { order(created_at: :asc) }, class_name: 'GoodJob::Execution', foreign_key: 'active_job_id', inverse_of: :job
23
23
 
24
24
  # Only the most-recent unretried execution represents a "Job"
25
25
  default_scope { where(retried_good_job_id: nil) }
@@ -27,11 +27,17 @@ module GoodJob
27
27
  # Get Jobs with given class name
28
28
  # @!method job_class
29
29
  # @!scope class
30
- # @param string [String]
31
- # Execution class name
30
+ # @param string [String] Execution class name
32
31
  # @return [ActiveRecord::Relation]
33
32
  scope :job_class, ->(job_class) { where("serialized_params->>'job_class' = ?", job_class) }
34
33
 
34
+ # Get Jobs finished before the given timestamp.
35
+ # @!method finished_before(timestamp)
36
+ # @!scope class
37
+ # @param timestamp (DateTime, Time)
38
+ # @return [ActiveRecord::Relation]
39
+ scope :finished_before, ->(timestamp) { where(arel_table['finished_at'].lteq(timestamp)) }
40
+
35
41
  # First execution will run in the future
36
42
  scope :scheduled, -> { where(finished_at: nil).where('COALESCE(scheduled_at, created_at) > ?', DateTime.current).where("(serialized_params->>'executions')::integer < 2") }
37
43
  # Execution errored, will run in the future
@@ -27,7 +27,7 @@ module GoodJob
27
27
  # @param queues [String, nil] determines which queues to execute jobs from when +execution_mode+ is set to +:async+. See {file:README.md#optimize-queues-threads-and-processes} for more details on the format of this string. You can also set this with the environment variable +GOOD_JOB_QUEUES+. Defaults to +"*"+.
28
28
  # @param poll_interval [Integer, nil] sets the number of seconds between polls for jobs when +execution_mode+ is set to +:async+. You can also set this with the environment variable +GOOD_JOB_POLL_INTERVAL+. Defaults to +1+.
29
29
  # @param start_async_on_initialize [Boolean] whether to start the async scheduler when the adapter is initialized.
30
- def initialize(execution_mode: nil, queues: nil, max_threads: nil, poll_interval: nil, start_async_on_initialize: Rails.application.initialized?)
30
+ def initialize(execution_mode: nil, queues: nil, max_threads: nil, poll_interval: nil, start_async_on_initialize: GoodJob.async_ready?)
31
31
  @configuration = GoodJob::Configuration.new(
32
32
  {
33
33
  execution_mode: execution_mode,
@@ -149,7 +149,7 @@ module GoodJob
149
149
  def in_server_process?
150
150
  return @_in_server_process if defined? @_in_server_process
151
151
 
152
- @_in_server_process = Rails.const_defined?('Server') ||
152
+ @_in_server_process = Rails.const_defined?(:Server) ||
153
153
  caller.grep(%r{config.ru}).any? || # EXAMPLE: config.ru:3:in `block in <main>' OR config.ru:3:in `new_from_string'
154
154
  caller.grep(%{/rack/handler/}).any? || # EXAMPLE: iodine-0.7.44/lib/rack/handler/iodine.rb:13:in `start'
155
155
  (Concurrent.on_jruby? && caller.grep(%r{jruby/rack/rails_booter}).any?) # EXAMPLE: uri:classloader:/jruby/rack/rails_booter.rb:83:in `load_environment'
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GoodJob # :nodoc:
4
+ # Extends GoodJob module to track Rails boot dependencies.
5
+ module Dependencies
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ # @!attribute [rw] _rails_after_initialize_hook_called
10
+ # @!scope class
11
+ # Whether Railtie.after_initialize has been called yet (default: +false+).
12
+ # This will be set on but before +Rails.application.initialize?+ is +true+.
13
+ # @return [Boolean]
14
+ mattr_accessor :_rails_after_initialize_hook_called, default: false
15
+
16
+ # @!attribute [rw] _active_job_loaded
17
+ # @!scope class
18
+ # Whether ActiveJob has loaded (default: +false+).
19
+ # @return [Boolean]
20
+ mattr_accessor :_active_job_loaded, default: false
21
+
22
+ # @!attribute [rw] _active_record_loaded
23
+ # @!scope class
24
+ # Whether ActiveRecord has loaded (default: +false+).
25
+ # @return [Boolean]
26
+ mattr_accessor :_active_record_loaded, default: false
27
+ end
28
+
29
+ class_methods do
30
+ # Whether GoodJob's has been initialized as of the calling of +Railtie.after_initialize+.
31
+ # @return [Boolean]
32
+ def async_ready?
33
+ Rails.application.initialized? || (
34
+ _rails_after_initialize_hook_called &&
35
+ _active_job_loaded &&
36
+ _active_record_loaded
37
+ )
38
+ end
39
+
40
+ def start_async_adapters
41
+ return unless async_ready?
42
+
43
+ GoodJob::Adapter.instances
44
+ .select(&:execute_async?)
45
+ .reject(&:async_started?)
46
+ .each(&:start_async)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -51,6 +51,8 @@ module GoodJob
51
51
  end
52
52
  end
53
53
 
54
+ belongs_to :job, class_name: 'GoodJob::ActiveJobJob', foreign_key: 'active_job_id', primary_key: 'active_job_id', optional: true, inverse_of: :executions
55
+
54
56
  # Get Jobs with given ActiveJob ID
55
57
  # @!method active_job_id
56
58
  # @!scope class
@@ -34,9 +34,18 @@ module GoodJob
34
34
  next if query.blank?
35
35
 
36
36
  tsvector = "(to_tsvector('english', serialized_params) || to_tsvector('english', id::text) || to_tsvector('english', COALESCE(error, '')::text))"
37
- where("#{tsvector} @@ to_tsquery(?)", query)
38
- .order(sanitize_sql_for_order([Arel.sql("ts_rank(#{tsvector}, to_tsquery(?))"), query]) => 'DESC')
37
+ to_tsquery_function = database_supports_websearch_to_tsquery? ? 'websearch_to_tsquery' : 'plainto_tsquery'
38
+ where("#{tsvector} @@ #{to_tsquery_function}(?)", query)
39
+ .order(sanitize_sql_for_order([Arel.sql("ts_rank(#{tsvector}, #{to_tsquery_function}(?))"), query]) => 'DESC')
39
40
  end)
40
41
  end
42
+
43
+ class_methods do
44
+ def database_supports_websearch_to_tsquery?
45
+ return @_database_supports_websearch_to_tsquery if defined?(@_database_supports_websearch_to_tsquery)
46
+
47
+ @_database_supports_websearch_to_tsquery = connection.postgresql_version >= 110000
48
+ end
49
+ end
41
50
  end
42
51
  end
@@ -16,9 +16,6 @@ module GoodJob # :nodoc:
16
16
 
17
17
  include Notifier::ProcessRegistration
18
18
 
19
- # Raised if the Database adapter does not implement LISTEN.
20
- AdapterCannotListenError = Class.new(StandardError)
21
-
22
19
  # Default Postgres channel for LISTEN/NOTIFY
23
20
  CHANNEL = 'good_job'
24
21
  # Defaults for instance of Concurrent::ThreadPoolExecutor
@@ -129,8 +126,6 @@ module GoodJob # :nodoc:
129
126
  # @!visibility private
130
127
  # @return [void]
131
128
  def listen_observer(_time, _result, thread_error)
132
- return if thread_error.is_a? AdapterCannotListenError
133
-
134
129
  if thread_error
135
130
  GoodJob._on_thread_error(thread_error)
136
131
  ActiveSupport::Notifications.instrument("notifier_notify_error.good_job", { error: thread_error })
@@ -214,6 +209,15 @@ module GoodJob # :nodoc:
214
209
  raw_connection.wait_for_notify(WAIT_INTERVAL) do |channel, _pid, payload|
215
210
  yield(channel, payload)
216
211
  end
212
+ elsif raw_connection.respond_to?(:jdbc_connection)
213
+ raw_connection.execute_query("SELECT 1")
214
+ notifications = raw_connection.jdbc_connection.getNotifications
215
+ Array(notifications).each do |notification|
216
+ channel = notification.getName
217
+ payload = notification.getParameter
218
+ yield(channel, payload)
219
+ end
220
+ sleep WAIT_INTERVAL
217
221
  else
218
222
  sleep WAIT_INTERVAL
219
223
  end
@@ -34,8 +34,27 @@ module GoodJob
34
34
  end
35
35
 
36
36
  initializer "good_job.start_async" do
37
+ # This hooks into the hookable places during Rails boot, which is unfortunately not Rails.application.initialized?
38
+ # If an Adapter is initialized during boot, we want to want to start its async executors once the framework dependencies have loaded.
39
+ # When exactly that happens is out of our control because gems or application code may touch things earlier than expected.
40
+ # For example, as of Rails 6.1, if an ActiveRecord model is touched during boot, that triggers ActiveRecord to load,
41
+ # which touches DestroyAssociationAsyncJob, which loads ActiveJob, which may initialize a GoodJob::Adapter, all of which
42
+ # happens _before_ ActiveRecord finishes loading. GoodJob will deadlock if an async executor is started in the middle of
43
+ # ActiveRecord loading.
44
+
37
45
  config.after_initialize do
38
- GoodJob::Adapter.instances.each(&:start_async)
46
+ ActiveSupport.on_load(:active_record) do
47
+ GoodJob._active_record_loaded = true
48
+ GoodJob.start_async_adapters
49
+ end
50
+
51
+ ActiveSupport.on_load(:active_job) do
52
+ GoodJob._active_job_loaded = true
53
+ GoodJob.start_async_adapters
54
+ end
55
+
56
+ GoodJob._rails_after_initialize_hook_called = true
57
+ GoodJob.start_async_adapters
39
58
  end
40
59
  end
41
60
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module GoodJob
3
3
  # GoodJob gem version.
4
- VERSION = '2.8.0'
4
+ VERSION = '2.9.2'
5
5
  end
data/lib/good_job.rb CHANGED
@@ -18,6 +18,8 @@ require "good_job/railtie"
18
18
  #
19
19
  # +GoodJob+ is the top-level namespace and exposes configuration attributes.
20
20
  module GoodJob
21
+ include GoodJob::Dependencies
22
+
21
23
  DEFAULT_LOGGER = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new($stdout))
22
24
 
23
25
  # @!attribute [rw] active_record_parent_class
@@ -138,9 +140,11 @@ module GoodJob
138
140
  timestamp = Time.current - older_than
139
141
 
140
142
  ActiveSupport::Notifications.instrument("cleanup_preserved_jobs.good_job", { older_than: older_than, timestamp: timestamp }) do |payload|
141
- deleted_records_count = GoodJob::Execution.finished(timestamp).delete_all
143
+ old_jobs = GoodJob::ActiveJobJob.where('finished_at <= ?', timestamp)
144
+ old_jobs_count = old_jobs.count
142
145
 
143
- payload[:deleted_records_count] = deleted_records_count
146
+ GoodJob::Execution.where(job: old_jobs).delete_all
147
+ payload[:deleted_records_count] = old_jobs_count
144
148
  end
145
149
  end
146
150
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-31 00:00:00.000000000 Z
11
+ date: 2022-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -405,6 +405,7 @@ files:
405
405
  - lib/generators/good_job/templates/update/migrations/02_add_cron_at_to_good_jobs.rb.erb
406
406
  - lib/generators/good_job/templates/update/migrations/03_add_cron_key_cron_at_index_to_good_jobs.rb.erb
407
407
  - lib/generators/good_job/templates/update/migrations/04_create_good_job_processes.rb.erb
408
+ - lib/generators/good_job/templates/update/migrations/04_index_good_job_jobs_on_finished_at.rb.erb
408
409
  - lib/generators/good_job/update_generator.rb
409
410
  - lib/good_job.rb
410
411
  - lib/good_job/active_job_extensions.rb
@@ -420,6 +421,7 @@ files:
420
421
  - lib/good_job/cron_manager.rb
421
422
  - lib/good_job/current_thread.rb
422
423
  - lib/good_job/daemon.rb
424
+ - lib/good_job/dependencies.rb
423
425
  - lib/good_job/execution.rb
424
426
  - lib/good_job/execution_result.rb
425
427
  - lib/good_job/filterable.rb
@@ -445,6 +447,7 @@ metadata:
445
447
  documentation_uri: https://rdoc.info/github/bensheldon/good_job
446
448
  homepage_uri: https://github.com/bensheldon/good_job
447
449
  source_code_uri: https://github.com/bensheldon/good_job
450
+ rubygems_mfa_required: 'true'
448
451
  post_install_message:
449
452
  rdoc_options:
450
453
  - "--title"
@@ -468,7 +471,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
468
471
  - !ruby/object:Gem::Version
469
472
  version: '0'
470
473
  requirements: []
471
- rubygems_version: 3.2.30
474
+ rubygems_version: 3.1.6
472
475
  signing_key:
473
476
  specification_version: 4
474
477
  summary: A multithreaded, Postgres-based ActiveJob backend for Ruby on Rails