good_job 3.18.1 → 3.18.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2573770a9539b895705eee99e074ec34cc74a1b2fffc491c6b01fe2218792bf3
4
- data.tar.gz: 49ae57e1ccfd0cf54421c349b1e0659dab195530f89ecce2bd6f29c37315e86d
3
+ metadata.gz: 930bb77e947ac155ee655210ab15ef32ac40fc2d6487eaf80b0005d7e5675156
4
+ data.tar.gz: b3e26f0b7f4d60483a6d0646d5797654e447542b8d6cb9eca22e2cb7cbfaac78
5
5
  SHA512:
6
- metadata.gz: aa1cdc0760d2d139acd4f76d95aab2093480930dd04b1a93673510497abb0f5d589ff1d71741d4e6f940d0c983bb003cbadeb06d9702a7b1165ba0f45bb13a47
7
- data.tar.gz: 7184e6f9816441a85d2d2574482fbb36ea39a3c0f76bb9a5169df9ee7ad63e7a5f150f110087eba9938bfc87af79745c4a9427391906a04457ed1993b7c2f6f2
6
+ metadata.gz: d92deaa0fa930cd8e8bf9b6b51f37c6d8ec1b75d221d939b6b5d2cb2ec30153931873951bbfca9af5dd24867e6131133f865368845a2cf783e8212137ed3bd76
7
+ data.tar.gz: 0c3ff2fd89cb38061ab145d74180596334fc8f38cba5f2a61d11fcf791d03534b823361bd9546cea4cea316d04d3cfba979d459b1b3d8185386298cdb71593a0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## [v3.18.3](https://github.com/bensheldon/good_job/tree/v3.18.3) (2023-09-16)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.18.2...v3.18.3)
6
+
7
+ **Fixed bugs:**
8
+
9
+ - Allow Probe Server's `/connect` to handle a certain number of reconnects before statusing [\#1075](https://github.com/bensheldon/good_job/pull/1075) ([bensheldon](https://github.com/bensheldon))
10
+
11
+ **Closed issues:**
12
+
13
+ - ActiveRecord::RecordNotUnique good\_jobs.id error in rspec test suite [\#1072](https://github.com/bensheldon/good_job/issues/1072)
14
+ - Probe failures on heavy usage of dashboard\(?\) [\#1068](https://github.com/bensheldon/good_job/issues/1068)
15
+
16
+ **Merged pull requests:**
17
+
18
+ - Bump actions/checkout from 3 to 4 [\#1070](https://github.com/bensheldon/good_job/pull/1070) ([dependabot[bot]](https://github.com/apps/dependabot))
19
+ - Add Skylight for demo site; create distinct development, lint, demo, production Gemfile groups; a little bit of Rubocop [\#1069](https://github.com/bensheldon/good_job/pull/1069) ([bensheldon](https://github.com/bensheldon))
20
+ - Add JRuby 9.4 to testing matrix; nerf ActiveJob::TestQueueAdapter overrides [\#1067](https://github.com/bensheldon/good_job/pull/1067) ([bensheldon](https://github.com/bensheldon))
21
+ - Reorganize dependencies to make booting JRuby easier [\#1066](https://github.com/bensheldon/good_job/pull/1066) ([bensheldon](https://github.com/bensheldon))
22
+ - Slight refactoring to CronEntry [\#1063](https://github.com/bensheldon/good_job/pull/1063) ([bensheldon](https://github.com/bensheldon))
23
+
24
+ ## [v3.18.2](https://github.com/bensheldon/good_job/tree/v3.18.2) (2023-09-02)
25
+
26
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.18.1...v3.18.2)
27
+
28
+ **Fixed bugs:**
29
+
30
+ - Fix compatibility with Global ID v1.2.0 [\#1064](https://github.com/bensheldon/good_job/pull/1064) ([bensheldon](https://github.com/bensheldon))
31
+
32
+ **Merged pull requests:**
33
+
34
+ - Bump pg from 1.5.3 to 1.5.4 [\#1061](https://github.com/bensheldon/good_job/pull/1061) ([dependabot[bot]](https://github.com/apps/dependabot))
35
+
3
36
  ## [v3.18.1](https://github.com/bensheldon/good_job/tree/v3.18.1) (2023-08-30)
4
37
 
5
38
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.18.0...v3.18.1)
@@ -16,7 +16,7 @@ module GoodJob
16
16
  end
17
17
 
18
18
  def default_base_query
19
- GoodJob::BatchRecord.all.includes(:jobs)
19
+ GoodJob::BatchRecord.includes(:jobs)
20
20
  end
21
21
  end
22
22
  end
@@ -59,6 +59,10 @@ module GoodJob
59
59
  end
60
60
  end
61
61
 
62
+ def self.primary_key
63
+ :id
64
+ end
65
+
62
66
  def self.find(id)
63
67
  new _record: BatchRecord.find(id)
64
68
  end
@@ -60,29 +60,15 @@ module GoodJob # :nodoc:
60
60
 
61
61
  def next_at(previously_at: nil)
62
62
  if cron_proc?
63
- result = Rails.application.executor.wrap { cron.call(previously_at || last_at) }
64
- return Fugit.parse(result).next_time.to_t if result.is_a?(String)
65
-
66
- return result
67
-
63
+ result = Rails.application.executor.wrap { cron.call(previously_at || last_job_at) }
64
+ if result.is_a?(String)
65
+ Fugit.parse(result).next_time.to_t
66
+ else
67
+ result
68
+ end
69
+ else
70
+ fugit.next_time.to_t
68
71
  end
69
- fugit.next_time.to_t
70
- end
71
-
72
- def schedule
73
- return "Custom schedule" if cron_proc?
74
-
75
- fugit.original
76
- end
77
-
78
- def jobs
79
- GoodJob::Job.where(cron_key: key)
80
- end
81
-
82
- def last_at
83
- return if last_job.blank?
84
-
85
- (last_job.cron_at || last_job.created_at).localtime
86
72
  end
87
73
 
88
74
  def enabled?
@@ -113,15 +99,11 @@ module GoodJob # :nodoc:
113
99
  false
114
100
  end
115
101
 
116
- def last_job
117
- jobs.order("cron_at DESC NULLS LAST").first
118
- end
119
-
120
102
  def display_properties
121
103
  {
122
104
  key: key,
123
105
  class: job_class,
124
- cron: schedule,
106
+ cron: display_schedule,
125
107
  set: display_property(set),
126
108
  description: display_property(description),
127
109
  }.tap do |properties|
@@ -130,6 +112,24 @@ module GoodJob # :nodoc:
130
112
  end
131
113
  end
132
114
 
115
+ def display_schedule
116
+ cron_proc? ? display_property(cron) : fugit.original
117
+ end
118
+
119
+ def jobs
120
+ GoodJob::Job.where(cron_key: key)
121
+ end
122
+
123
+ def last_job
124
+ jobs.order("cron_at DESC NULLS LAST").first
125
+ end
126
+
127
+ def last_job_at
128
+ return if last_job.blank?
129
+
130
+ (last_job.cron_at || last_job.created_at).localtime
131
+ end
132
+
133
133
  private
134
134
 
135
135
  def cron
@@ -163,7 +163,7 @@ module GoodJob # :nodoc:
163
163
  case value
164
164
  when NilClass
165
165
  "None"
166
- when Proc
166
+ when Callable
167
167
  "Lambda/Callable"
168
168
  else
169
169
  value
@@ -31,7 +31,7 @@
31
31
  <div class="col-12 col-lg-2 text-wrap"><%= tag.span tag.code(cron_entry.job_class), class: "fs-5 mb-0" %></div>
32
32
  <div class="col-6 col-lg-2 text-wrap">
33
33
  <div class="d-lg-none small text-muted mt-1"><%= t "good_job.models.cron.schedule" %></div>
34
- <span class="font-monospace fw-bold"><%= cron_entry.schedule %></span>
34
+ <span class="font-monospace fw-bold"><%= cron_entry.display_schedule %></span>
35
35
  </div>
36
36
  <div class="col-6 col-lg-2 text-wrap small">
37
37
  <div class="d-lg-none small text-muted mt-1"><%= t "good_job.models.cron.next_scheduled" %></div>
@@ -40,7 +40,7 @@
40
40
  <div class="col-6 col-lg-2 text-wrap small">
41
41
  <% if cron_entry.last_job.present? %>
42
42
  <div class="d-lg-none small text-muted mt-1"><%= t "good_job.models.cron.last_run" %></div>
43
- <%= link_to relative_time(cron_entry.last_at), cron_entry_path(cron_entry), title: "Job #{cron_entry.last_job.id}" %>
43
+ <%= link_to relative_time(cron_entry.last_job_at), cron_entry_path(cron_entry), title: "Job #{cron_entry.last_job.id}" %>
44
44
  <% end %>
45
45
  </div>
46
46
  <div class="col d-flex gap-3 justify-content-end">
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GoodJob
4
+ # An object that has case-equality to a Proc or Lambda by responding to #call.
5
+ # This can be used to duck-type match in a case statement.
6
+ module Callable
7
+ # Whether the object responds to #call
8
+ def self.===(other)
9
+ other.respond_to?(:call)
10
+ end
11
+ end
12
+ end
@@ -24,6 +24,9 @@ module GoodJob # :nodoc:
24
24
  WAIT_INTERVAL = 1
25
25
  # Seconds to wait if database cannot be connected to
26
26
  RECONNECT_INTERVAL = 5
27
+ # Number of consecutive connection errors before reporting an error
28
+ CONNECTION_ERRORS_REPORTING_THRESHOLD = 6
29
+
27
30
  # Connection errors that will wait {RECONNECT_INTERVAL} before reconnecting
28
31
  CONNECTION_ERRORS = %w[
29
32
  ActiveRecord::ConnectionNotEstablished
@@ -31,7 +34,6 @@ module GoodJob # :nodoc:
31
34
  PG::UnableToSend
32
35
  PG::Error
33
36
  ].freeze
34
- CONNECTION_ERRORS_REPORTING_THRESHOLD = 3
35
37
 
36
38
  # @!attribute [r] instances
37
39
  # @!scope class
@@ -69,8 +71,8 @@ module GoodJob # :nodoc:
69
71
  @mutex = Mutex.new
70
72
  @shutdown_event = Concurrent::Event.new.tap(&:set)
71
73
  @running = Concurrent::AtomicBoolean.new(false)
72
- @connected = Concurrent::AtomicBoolean.new(false)
73
- @listening = Concurrent::AtomicBoolean.new(false)
74
+ @connected = Concurrent::Event.new
75
+ @listening = Concurrent::Event.new
74
76
  @connection_errors_count = Concurrent::AtomicFixnum.new(0)
75
77
  @connection_errors_reported = Concurrent::AtomicBoolean.new(false)
76
78
  @enable_listening = enable_listening
@@ -85,15 +87,25 @@ module GoodJob # :nodoc:
85
87
  end
86
88
 
87
89
  # Tests whether the notifier is active and has acquired a dedicated database connection.
90
+ # @param timeout [Numeric, nil] Seconds to wait for condition to be true, -1 is forever
88
91
  # @return [true, false, nil]
89
- def connected?
90
- @connected.true?
92
+ def connected?(timeout: nil)
93
+ if timeout.nil?
94
+ @connected.set?
95
+ else
96
+ @connected.wait(timeout == -1 ? nil : timeout)
97
+ end
91
98
  end
92
99
 
93
100
  # Tests whether the notifier is listening for new messages.
101
+ # @param timeout [Numeric, nil] Seconds to wait for condition to be true, -1 is forever
94
102
  # @return [true, false, nil]
95
- def listening?
96
- @listening.true?
103
+ def listening?(timeout: nil)
104
+ if timeout.nil?
105
+ @listening.set?
106
+ else
107
+ @listening.wait(timeout == -1 ? nil : timeout)
108
+ end
97
109
  end
98
110
 
99
111
  def shutdown?
@@ -114,11 +126,12 @@ module GoodJob # :nodoc:
114
126
 
115
127
  if @executor.shutdown? || @task&.complete?
116
128
  # clean up in the even the executor is killed
117
- @connected.make_false
118
- @listening.make_false
129
+ @connected.reset
130
+ @listening.reset
119
131
  @shutdown_event.set
120
132
  else
121
133
  @shutdown_event.wait(timeout == -1 ? nil : timeout) unless timeout.nil?
134
+ @connected.reset if @shutdown_event.set?
122
135
  end
123
136
  @shutdown_event.set?
124
137
  end
@@ -152,6 +165,7 @@ module GoodJob # :nodoc:
152
165
  if connection_error
153
166
  @connection_errors_count.increment
154
167
  if @connection_errors_reported.false? && @connection_errors_count.value >= CONNECTION_ERRORS_REPORTING_THRESHOLD
168
+ @connected.reset
155
169
  GoodJob._on_thread_error(thread_error)
156
170
  @connection_errors_reported.make_true
157
171
  end
@@ -180,15 +194,17 @@ module GoodJob # :nodoc:
180
194
  end
181
195
 
182
196
  def create_listen_task(delay: 0)
183
- @task = Concurrent::ScheduledTask.new(delay, args: [@recipients, @running, @executor, @enable_listening, @listening], executor: @executor) do |thr_recipients, thr_running, thr_executor, thr_enable_listening, thr_listening|
197
+ @task = Concurrent::ScheduledTask.new(delay, args: [@recipients, @running, @executor, @enable_listening, @connected, @listening], executor: @executor) do |thr_recipients, thr_running, thr_executor, thr_enable_listening, thr_connected, thr_listening|
184
198
  with_connection do
199
+ thr_connected.set
200
+
185
201
  begin
186
202
  Rails.application.executor.wrap do
187
203
  run_callbacks :listen do
188
204
  if thr_enable_listening
189
205
  ActiveSupport::Notifications.instrument("notifier_listen.good_job") do
190
206
  connection.execute("LISTEN #{CHANNEL}")
191
- thr_listening.make_true
207
+ thr_listening.set
192
208
  end
193
209
  end
194
210
  end
@@ -216,7 +232,7 @@ module GoodJob # :nodoc:
216
232
  run_callbacks :unlisten do
217
233
  if thr_enable_listening
218
234
  ActiveSupport::Notifications.instrument("notifier_unlisten.good_job") do
219
- thr_listening.make_false
235
+ thr_listening.reset
220
236
  connection.execute("UNLISTEN *")
221
237
  end
222
238
  end
@@ -237,11 +253,9 @@ module GoodJob # :nodoc:
237
253
  end
238
254
  end
239
255
  connection.execute("SET application_name = #{connection.quote(self.class.name)}")
240
- @connected.make_true
241
256
 
242
257
  yield
243
258
  ensure
244
- @connected.make_false
245
259
  connection&.disconnect!
246
260
  self.connection = nil
247
261
  end
@@ -37,7 +37,7 @@ module GoodJob
37
37
  started ? [200, {}, ["Started"]] : [503, {}, ["Not started"]]
38
38
  when '/status/connected'
39
39
  connected = GoodJob::Scheduler.instances.any? && GoodJob::Scheduler.instances.all?(&:running?) &&
40
- GoodJob::Notifier.instances.any? && GoodJob::Notifier.instances.all?(&:listening?)
40
+ GoodJob::Notifier.instances.any? && GoodJob::Notifier.instances.all?(&:connected?)
41
41
  connected ? [200, {}, ["Connected"]] : [503, {}, ["Not connected"]]
42
42
  else
43
43
  [404, {}, ["Not found"]]
@@ -2,7 +2,7 @@
2
2
 
3
3
  module GoodJob
4
4
  # GoodJob gem version.
5
- VERSION = '3.18.1'
5
+ VERSION = '3.18.3'
6
6
 
7
7
  # GoodJob version as Gem::Version object
8
8
  GEM_VERSION = Gem::Version.new(VERSION)
data/lib/good_job.rb CHANGED
@@ -16,6 +16,7 @@ require "good_job/active_job_extensions/notify_options"
16
16
 
17
17
  require "good_job/assignable_connection"
18
18
  require "good_job/bulk"
19
+ require "good_job/callable"
19
20
  require "good_job/capsule"
20
21
  require "good_job/cleanup_tracker"
21
22
  require "good_job/cli"
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: 3.18.1
4
+ version: 3.18.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-30 00:00:00.000000000 Z
11
+ date: 2023-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -122,62 +122,6 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: dotenv
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: 2.7.6
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: 2.7.6
139
- - !ruby/object:Gem::Dependency
140
- name: foreman
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: gem-release
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
- - !ruby/object:Gem::Dependency
168
- name: github_changelog_generator
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: '0'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: '0'
181
125
  - !ruby/object:Gem::Dependency
182
126
  name: kramdown
183
127
  requirement: !ruby/object:Gem::Requirement
@@ -408,6 +352,7 @@ files:
408
352
  - lib/good_job/adapter.rb
409
353
  - lib/good_job/assignable_connection.rb
410
354
  - lib/good_job/bulk.rb
355
+ - lib/good_job/callable.rb
411
356
  - lib/good_job/capsule.rb
412
357
  - lib/good_job/cleanup_tracker.rb
413
358
  - lib/good_job/cli.rb