good_job 1.3.5 → 1.3.6

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: 46b04fbfe44919834c406101ee18f2b53f5cc05e076525f7243e346fa966ca94
4
- data.tar.gz: 798738a1f2b0c7f21457921c2c640cdc78151a09262dfa7d8a383e8778282b9d
3
+ metadata.gz: 8b5d625792328475faca2679c6718f344fc5162cac639be09f91197c998f2fdf
4
+ data.tar.gz: 4aef2c4ae814f2a0606c18e875c91e56f8a1411394c37d45f4e1141be719f080
5
5
  SHA512:
6
- metadata.gz: 841c85e7b4d9fa28d1fcdbb7c6a48771438f24ae33a264a80afdff1c9730a3438b98aa5d82f54bd1d4c979b2dab64997fbf6d64036bc96fdac6c851f70e0f68f
7
- data.tar.gz: 9c2d11c56e3db986aa5bbecc85a317396a19ba1c838b97d32cd16f21b9cd29b6c154be817879d8c8a8925da645d298442c0ebc39aba3d5bba707ed01558b55c5
6
+ metadata.gz: d309e288c89c65ec809cf7f9e138026b229aed9abb6ee667343c56ed1e96fb0833be36b7e1f1c6b064168957f537d572e2ceb5ecad0f6e754108762ace9fbd3b
7
+ data.tar.gz: c1b83122c14edcbe619c6198fae270f9dbb0398888232f96e8956be23ca0f5798422181a21ea08735a0089ad3a92c0405ee69731a8a205f3fe9c99ba2b27bb36
@@ -1,9 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.3.6](https://github.com/bensheldon/good_job/tree/v1.3.6) (2020-12-30)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.5...v1.3.6)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Call GoodJob.on\_thread\_error when Notifier thread raises exception [\#185](https://github.com/bensheldon/good_job/pull/185) ([bensheldon](https://github.com/bensheldon))
10
+ - Improve dashboard UI, fix button state, add unfiltering [\#181](https://github.com/bensheldon/good_job/pull/181) ([bensheldon](https://github.com/bensheldon))
11
+
12
+ **Fixed bugs:**
13
+
14
+ - Replace ActiveRecord execute usage and avoid potential memory leakage [\#187](https://github.com/bensheldon/good_job/issues/187)
15
+ - Does good\_job hold on to advisory locks for finished jobs? [\#177](https://github.com/bensheldon/good_job/issues/177)
16
+
17
+ **Merged pull requests:**
18
+
19
+ - Run tests with Rails default configuration to enable Zeitwerk [\#190](https://github.com/bensheldon/good_job/pull/190) ([bensheldon](https://github.com/bensheldon))
20
+ - Update all Lockable queries to use exec\_query instead of execute; clear async\_exec results [\#189](https://github.com/bensheldon/good_job/pull/189) ([bensheldon](https://github.com/bensheldon))
21
+ - Have Lockable\#advisory\_locked? directly query pg\_locks table [\#188](https://github.com/bensheldon/good_job/pull/188) ([bensheldon](https://github.com/bensheldon))
22
+ - Update development gems, including Rails v6.1 and Rails HEAD [\#186](https://github.com/bensheldon/good_job/pull/186) ([bensheldon](https://github.com/bensheldon))
23
+ - Update Appraisals for Rails 6.1 [\#183](https://github.com/bensheldon/good_job/pull/183) ([bensheldon](https://github.com/bensheldon))
24
+ - Add Ruby 3 to CI test matrix [\#182](https://github.com/bensheldon/good_job/pull/182) ([bensheldon](https://github.com/bensheldon))
25
+
3
26
  ## [v1.3.5](https://github.com/bensheldon/good_job/tree/v1.3.5) (2020-12-17)
4
27
 
5
28
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.4...v1.3.5)
6
29
 
30
+ **Fixed bugs:**
31
+
32
+ - Ensure advisory lock CTE is MATERIALIZED on Postgres v12+ [\#179](https://github.com/bensheldon/good_job/pull/179) ([bensheldon](https://github.com/bensheldon))
33
+ - Ensure that deleted jobs are unlocked [\#178](https://github.com/bensheldon/good_job/pull/178) ([bensheldon](https://github.com/bensheldon))
34
+
7
35
  **Closed issues:**
8
36
 
9
37
  - not running jobs [\#168](https://github.com/bensheldon/good_job/issues/168)
@@ -11,15 +39,13 @@
11
39
 
12
40
  **Merged pull requests:**
13
41
 
14
- - Ensure advisory lock CTE is MATERIALIZED on Postgres v12+ [\#179](https://github.com/bensheldon/good_job/pull/179) ([bensheldon](https://github.com/bensheldon))
15
- - Ensure that deleted jobs are unlocked [\#178](https://github.com/bensheldon/good_job/pull/178) ([bensheldon](https://github.com/bensheldon))
16
42
  - Add Appraisal for Rails 6.1-rc2 [\#175](https://github.com/bensheldon/good_job/pull/175) ([bensheldon](https://github.com/bensheldon))
17
43
 
18
44
  ## [v1.3.4](https://github.com/bensheldon/good_job/tree/v1.3.4) (2020-12-02)
19
45
 
20
46
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.3...v1.3.4)
21
47
 
22
- **Merged pull requests:**
48
+ **Fixed bugs:**
23
49
 
24
50
  - Fix job ordering for Rails 6.1 [\#174](https://github.com/bensheldon/good_job/pull/174) ([morgoth](https://github.com/morgoth))
25
51
 
@@ -27,7 +53,7 @@
27
53
 
28
54
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v1.3.2...v1.3.3)
29
55
 
30
- **Merged pull requests:**
56
+ **Implemented enhancements:**
31
57
 
32
58
  - UI: Admin UI with filters and space efficient layout [\#173](https://github.com/bensheldon/good_job/pull/173) ([zealot128](https://github.com/zealot128))
33
59
 
@@ -428,6 +454,7 @@
428
454
  **Merged pull requests:**
429
455
 
430
456
  - Improve ActiveRecord usage for advisory locking [\#24](https://github.com/bensheldon/good_job/pull/24) ([bensheldon](https://github.com/bensheldon))
457
+ - Remove support for Rails 5.1 [\#23](https://github.com/bensheldon/good_job/pull/23) ([bensheldon](https://github.com/bensheldon))
431
458
 
432
459
  ## [v0.3.0](https://github.com/bensheldon/good_job/tree/v0.3.0) (2020-03-22)
433
460
 
@@ -446,7 +473,6 @@
446
473
 
447
474
  **Merged pull requests:**
448
475
 
449
- - Remove support for Rails 5.1 [\#23](https://github.com/bensheldon/good_job/pull/23) ([bensheldon](https://github.com/bensheldon))
450
476
  - Gracefully shutdown Scheduler when executable receives TERM or INT [\#17](https://github.com/bensheldon/good_job/pull/17) ([bensheldon](https://github.com/bensheldon))
451
477
  - Update Appraisals [\#16](https://github.com/bensheldon/good_job/pull/16) ([bensheldon](https://github.com/bensheldon))
452
478
 
@@ -42,11 +42,11 @@ module GoodJob
42
42
  GoodJob::Job.group("serialized_params->>'job_class'").count
43
43
  end
44
44
 
45
- def to_query(override)
45
+ def to_params(override)
46
46
  {
47
47
  state: params[:state],
48
48
  job_class: params[:job_class],
49
- }.merge(override).delete_if { |_, v| v.nil? }.to_query
49
+ }.merge(override).delete_if { |_, v| v.nil? }
50
50
  end
51
51
  end
52
52
 
@@ -8,18 +8,30 @@
8
8
  <small>Filter by job class</small>
9
9
  <br>
10
10
  <% @filter.job_classes.each do |name, count| %>
11
- <a href='<%= request.path + "?#{@filter.to_query(job_class: name)}" %>' class='btn btn-sm btn-outline-secondary <%= "active" if params[:job_class] == name %>'>
12
- <%= name %> (<%= count %>)
13
- </a>
11
+ <% if params[:job_class] == name %>
12
+ <%= link_to(root_path(@filter.to_params(job_class: nil)), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
13
+ <%= name %> (<%= count %>)
14
+ <% end %>
15
+ <% else %>
16
+ <%= link_to(root_path(@filter.to_params(job_class: name)), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
17
+ <%= name %> (<%= count %>)
18
+ <% end %>
19
+ <% end %>
14
20
  <% end %>
15
21
  </div>
16
22
  <div>
17
23
  <small>Filter by state</small>
18
24
  <br>
19
25
  <% @filter.states.each do |name, count| %>
20
- <a href='<%= request.path + "?#{@filter.to_query(state: name)}" %>' class='btn btn-sm btn-outline-secondary <%= "active" if params[:state] == name %>'>
21
- <%= name %> (<%= count %>)
22
- </a>
26
+ <% if params[:state] == name %>
27
+ <%= link_to(root_path(@filter.to_params(state: nil)), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
28
+ <%= name %> (<%= count %>)
29
+ <% end %>
30
+ <% else %>
31
+ <%= link_to(root_path(@filter.to_params(state: name)), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
32
+ <%= name %> (<%= count %>)
33
+ <% end %>
34
+ <% end %>
23
35
  <% end %>
24
36
  </div>
25
37
  </div>
@@ -28,7 +40,7 @@
28
40
  <% if @filter.jobs.present? %>
29
41
  <%= render 'shared/jobs_table', jobs: @filter.jobs %>
30
42
 
31
- <nav aria-label="Job pagination">
43
+ <nav aria-label="Job pagination" class="mt-3">
32
44
  <ul class="pagination">
33
45
  <li class="page-item">
34
46
  <%= link_to({ after_scheduled_at: (@filter.last.scheduled_at || @filter.last.created_at), after_id: @filter.last.id }, class: "page-link") do %>
@@ -6,14 +6,14 @@
6
6
  <%= csp_meta_tag %>
7
7
 
8
8
  <style>
9
- <%= render file: GoodJob::Engine.root.join("app", "assets", "vendor", "bootstrap", "bootstrap.css") %>
10
- <%= render file: GoodJob::Engine.root.join("app", "assets", "vendor", "chartist", "chartist.css") %>
11
- <%= render file: GoodJob::Engine.root.join("app", "assets", "style.css") %>
9
+ <%== render file: GoodJob::Engine.root.join("app", "assets", "vendor", "bootstrap", "bootstrap.css") %>
10
+ <%== render file: GoodJob::Engine.root.join("app", "assets", "vendor", "chartist", "chartist.css") %>
11
+ <%== render file: GoodJob::Engine.root.join("app", "assets", "style.css") %>
12
12
  </style>
13
13
 
14
14
  <script>
15
- <%= render file: GoodJob::Engine.root.join("app", "assets", "vendor", "bootstrap", "bootstrap-native.js") %>
16
- <%= render file: GoodJob::Engine.root.join("app", "assets", "vendor", "chartist", "chartist.js") %>
15
+ <%== render file: GoodJob::Engine.root.join("app", "assets", "vendor", "bootstrap", "bootstrap-native.js") %>
16
+ <%== render file: GoodJob::Engine.root.join("app", "assets", "vendor", "chartist", "chartist.js") %>
17
17
  </script>
18
18
  </head>
19
19
  <body>
@@ -1,7 +1,7 @@
1
1
  <div id="chart"></div>
2
2
 
3
3
  <script>
4
- new Chartist.Line('#chart', <%= raw chart_data.to_json %>, {
4
+ new Chartist.Line('#chart', <%== chart_data.to_json %>, {
5
5
  height: '300px',
6
6
  fullWidth: true,
7
7
  chartPadding: {
@@ -1,26 +1,28 @@
1
- <div class="table-responsive">
2
- <table class="table table-bordered table-hover table-sm">
3
- <thead>
4
- <th>GoodJob ID</th>
5
- <th>ActiveJob ID</th>
6
- <th>Job Class</th>
7
- <th>Queue</th>
8
- <th>Scheduled At</th>
9
- <th>Error</th>
10
- <th>ActiveJob Params</th>
11
- </thead>
12
- <tbody>
13
- <% jobs.each do |job| %>
14
- <tr id="<%= dom_id(job) %>">
15
- <td><%= link_to job.id, active_job_path(job.serialized_params['job_id'], anchor: dom_id(job)) %></td>
16
- <td><%= link_to job.serialized_params['job_id'], active_job_path(job.serialized_params['job_id']) %></td>
17
- <td><%= job.serialized_params['job_class'] %></td>
18
- <td><%= job.queue_name %></td>
19
- <td><%= job.scheduled_at || job.created_at %></td>
20
- <td><%= job.error %></td>
21
- <td><pre><%= JSON.pretty_generate(job.serialized_params) %></pre></td>
22
- </tr>
23
- <% end %>
24
- </tbody>
25
- </table>
1
+ <div class="card my-3">
2
+ <div class="table-responsive">
3
+ <table class="table card-table table-bordered table-hover table-sm mb-0">
4
+ <thead>
5
+ <th>GoodJob ID</th>
6
+ <th>ActiveJob ID</th>
7
+ <th>Job Class</th>
8
+ <th>Queue</th>
9
+ <th>Scheduled At</th>
10
+ <th>Error</th>
11
+ <th>ActiveJob Params</th>
12
+ </thead>
13
+ <tbody>
14
+ <% jobs.each do |job| %>
15
+ <tr id="<%= dom_id(job) %>">
16
+ <td><%= link_to job.id, active_job_path(job.serialized_params['job_id'], anchor: dom_id(job)) %></td>
17
+ <td><%= link_to job.serialized_params['job_id'], active_job_path(job.serialized_params['job_id']) %></td>
18
+ <td><%= job.serialized_params['job_class'] %></td>
19
+ <td><%= job.queue_name %></td>
20
+ <td><%= job.scheduled_at || job.created_at %></td>
21
+ <td><%= job.error %></td>
22
+ <td><pre><%= JSON.pretty_generate(job.serialized_params) %></pre></td>
23
+ </tr>
24
+ <% end %>
25
+ </tbody>
26
+ </table>
27
+ </div>
26
28
  </div>
@@ -58,9 +58,7 @@ module GoodJob
58
58
  def rails_execution_mode
59
59
  if execution_mode(default: nil)
60
60
  execution_mode
61
- elsif Rails.env.development?
62
- :inline
63
- elsif Rails.env.test?
61
+ elsif Rails.env.development? || Rails.env.test?
64
62
  :inline
65
63
  else
66
64
  :external
@@ -139,7 +139,7 @@ module GoodJob
139
139
  unfinished.priority_ordered.only_scheduled.limit(1).with_advisory_lock do |good_jobs|
140
140
  good_job = good_jobs.first
141
141
  # TODO: Determine why some records are fetched without an advisory lock at all
142
- break unless good_job&.owns_advisory_lock?
142
+ break unless good_job&.executable?
143
143
 
144
144
  result, error = good_job.perform
145
145
  end
@@ -216,6 +216,12 @@ module GoodJob
216
216
  [result, job_error]
217
217
  end
218
218
 
219
+ # Tests whether this job is safe to be executed by this thread.
220
+ # @return [Boolean]
221
+ def executable?
222
+ self.class.unscoped.unfinished.owns_advisory_locked.exists?(id: id)
223
+ end
224
+
219
225
  private
220
226
 
221
227
  def execute
@@ -141,9 +141,9 @@ module GoodJob
141
141
  end
142
142
 
143
143
  def supports_cte_materialization_specifiers?
144
- return @supports_cte_materialization_specifiers if defined?(@supports_cte_materialization_specifiers)
144
+ return @_supports_cte_materialization_specifiers if defined?(@_supports_cte_materialization_specifiers)
145
145
 
146
- @supports_cte_materialization_specifiers = ActiveRecord::Base.connection.postgresql_version >= 120000
146
+ @_supports_cte_materialization_specifiers = ActiveRecord::Base.connection.postgresql_version >= 120000
147
147
  end
148
148
  end
149
149
 
@@ -153,10 +153,11 @@ module GoodJob
153
153
  # all remaining locks).
154
154
  # @return [Boolean] whether the lock was acquired.
155
155
  def advisory_lock
156
- where_sql = <<~SQL.squish
157
- pg_try_advisory_lock(('x' || substr(md5(:table_name || :id::text), 1, 16))::bit(64)::bigint)
156
+ query = <<~SQL.squish
157
+ SELECT 1 AS one
158
+ WHERE pg_try_advisory_lock(('x'||substr(md5($1 || $2::text), 1, 16))::bit(64)::bigint)
158
159
  SQL
159
- self.class.unscoped.exists?([where_sql, { table_name: self.class.table_name, id: send(self.class.primary_key) }])
160
+ self.class.connection.exec_query(query, 'GoodJob::Lockable Advisory Lock', [[nil, self.class.table_name], [nil, send(self.class.primary_key)]]).any?
160
161
  end
161
162
 
162
163
  # Releases an advisory lock on this record if it is locked by this database
@@ -166,9 +167,9 @@ module GoodJob
166
167
  def advisory_unlock
167
168
  query = <<~SQL.squish
168
169
  SELECT 1 AS one
169
- WHERE pg_advisory_unlock(('x'||substr(md5(:table_name || :id::text), 1, 16))::bit(64)::bigint)
170
+ WHERE pg_advisory_unlock(('x'||substr(md5($1 || $2::text), 1, 16))::bit(64)::bigint)
170
171
  SQL
171
- self.class.connection.execute(sanitize_sql_for_conditions([query, { table_name: self.class.table_name, id: send(self.class.primary_key) }])).ntuples.positive?
172
+ self.class.connection.exec_query(query, 'GoodJob::Lockable Advisory Unlock', [[nil, self.class.table_name], [nil, send(self.class.primary_key)]]).any?
172
173
  end
173
174
 
174
175
  # Acquires an advisory lock on this record or raises
@@ -205,13 +206,30 @@ module GoodJob
205
206
  # Tests whether this record has an advisory lock on it.
206
207
  # @return [Boolean]
207
208
  def advisory_locked?
208
- self.class.unscoped.advisory_locked.exists?(id: send(self.class.primary_key))
209
+ query = <<~SQL.squish
210
+ SELECT 1 AS one
211
+ FROM pg_locks
212
+ WHERE pg_locks.locktype = 'advisory'
213
+ AND pg_locks.objsubid = 1
214
+ AND pg_locks.classid = ('x' || substr(md5($1 || $2::text), 1, 16))::bit(32)::int
215
+ AND pg_locks.objid = (('x' || substr(md5($1 || $2::text), 1, 16))::bit(64) << 32)::bit(32)::int
216
+ SQL
217
+ self.class.connection.exec_query(query, 'GoodJob::Lockable Advisory Locked?', [[nil, self.class.table_name], [nil, send(self.class.primary_key)]]).any?
209
218
  end
210
219
 
211
220
  # Tests whether this record is locked by the current database session.
212
221
  # @return [Boolean]
213
222
  def owns_advisory_lock?
214
- self.class.unscoped.owns_advisory_locked.exists?(id: send(self.class.primary_key))
223
+ query = <<~SQL.squish
224
+ SELECT 1 AS one
225
+ FROM pg_locks
226
+ WHERE pg_locks.locktype = 'advisory'
227
+ AND pg_locks.objsubid = 1
228
+ AND pg_locks.classid = ('x' || substr(md5($1 || $2::text), 1, 16))::bit(32)::int
229
+ AND pg_locks.objid = (('x' || substr(md5($1 || $2::text), 1, 16))::bit(64) << 32)::bit(32)::int
230
+ AND pg_locks.pid = pg_backend_pid()
231
+ SQL
232
+ self.class.connection.exec_query(query, 'GoodJob::Lockable Owns Advisory Lock?', [[nil, self.class.table_name], [nil, send(self.class.primary_key)]]).any?
215
233
  end
216
234
 
217
235
  # Releases all advisory locks on the record that are held by the current
@@ -218,13 +218,13 @@ module GoodJob
218
218
  #
219
219
  %w(info debug warn error fatal unknown).each do |level|
220
220
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
221
- def #{level}(progname = nil, tags: [], &block)
222
- return unless logger
223
-
224
- tag_logger(*tags) do
225
- logger.#{level}(progname, &block)
226
- end
227
- end
221
+ def #{level}(progname = nil, tags: [], &block) # def info(progname = nil, tags: [], &block)
222
+ return unless logger # return unless logger
223
+ #
224
+ tag_logger(*tags) do # tag_logger(*tags) do
225
+ logger.#{level}(progname, &block) # logger.info(progname, &block)
226
+ end # end
227
+ end #
228
228
  METHOD
229
229
  end
230
230
  end
@@ -90,6 +90,18 @@ module GoodJob # :nodoc:
90
90
  !@pool.running?
91
91
  end
92
92
 
93
+ # Invoked on completion of ThreadPoolExecutor task
94
+ # @!visibility private
95
+ # @return [void]
96
+ def listen_observer(_time, _result, thread_error)
97
+ if thread_error
98
+ GoodJob.on_thread_error.call(thread_error) if GoodJob.on_thread_error.respond_to?(:call)
99
+ ActiveSupport::Notifications.instrument("notifier_notify_error.good_job", { error: thread_error })
100
+ end
101
+
102
+ listen unless shutdown?
103
+ end
104
+
93
105
  private
94
106
 
95
107
  def create_pool
@@ -100,7 +112,7 @@ module GoodJob # :nodoc:
100
112
  future = Concurrent::Future.new(args: [@recipients, @pool, @listening], executor: @pool) do |recipients, pool, listening|
101
113
  with_listen_connection do |conn|
102
114
  ActiveSupport::Notifications.instrument("notifier_listen.good_job") do
103
- conn.async_exec "LISTEN #{CHANNEL}"
115
+ conn.async_exec("LISTEN #{CHANNEL}").clear
104
116
  end
105
117
 
106
118
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
@@ -120,14 +132,11 @@ module GoodJob # :nodoc:
120
132
  listening.make_false
121
133
  end
122
134
  end
123
- end
124
- rescue StandardError => e
125
- ActiveSupport::Notifications.instrument("notifier_notify_error.good_job", { error: e })
126
- raise
127
- ensure
128
- @listening.make_false
129
- ActiveSupport::Notifications.instrument("notifier_unlisten.good_job") do
130
- conn.async_exec "UNLISTEN *"
135
+ ensure
136
+ listening.make_false
137
+ ActiveSupport::Notifications.instrument("notifier_unlisten.good_job") do
138
+ conn.async_exec("UNLISTEN *").clear
139
+ end
131
140
  end
132
141
  end
133
142
 
@@ -135,16 +144,12 @@ module GoodJob # :nodoc:
135
144
  future.execute
136
145
  end
137
146
 
138
- def listen_observer(_time, _result, _thread_error)
139
- listen unless shutdown?
140
- end
141
-
142
147
  def with_listen_connection
143
148
  ar_conn = ActiveRecord::Base.connection_pool.checkout.tap do |conn|
144
149
  ActiveRecord::Base.connection_pool.remove(conn)
145
150
  end
146
151
  pg_conn = ar_conn.raw_connection
147
- pg_conn.exec("SET application_name = #{pg_conn.escape_identifier(self.class.name)}")
152
+ pg_conn.async_exec("SET application_name = #{pg_conn.escape_identifier(self.class.name)}").clear
148
153
  yield pg_conn
149
154
  ensure
150
155
  ar_conn&.disconnect!
@@ -1,4 +1,4 @@
1
1
  module GoodJob
2
2
  # GoodJob gem version.
3
- VERSION = '1.3.5'.freeze
3
+ VERSION = '1.3.6'.freeze
4
4
  end
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: 1.3.5
4
+ version: 1.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-17 00:00:00.000000000 Z
11
+ date: 2020-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -441,7 +441,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
441
441
  - !ruby/object:Gem::Version
442
442
  version: '0'
443
443
  requirements: []
444
- rubygems_version: 3.1.4
444
+ rubygems_version: 3.2.3
445
445
  signing_key:
446
446
  specification_version: 4
447
447
  summary: A multithreaded, Postgres-based ActiveJob backend for Ruby on Rails