good_job 3.25.0 → 3.26.1

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: 47f288c089d005a2b97e5fe6d7bd8fb7094d48fb52565bacf0493b5e547f6516
4
- data.tar.gz: cf8cd69a7a1f64fee5172b7fd3b184d774eed0cd48d97ba0d01971af0d721646
3
+ metadata.gz: eedb4c5defcfa2e25d62147f5021bb868ee0a93b74ae680c46ea4e852212d0dc
4
+ data.tar.gz: d0124daaa3d93e7ace5b0764031c44cc06b03559286ebf1e5a36936e414bb50d
5
5
  SHA512:
6
- metadata.gz: 3c74189b7315da1fcb5747b285cb4d7837550dcf1456899f2d6f023065a893bd99c93a7e292415b6796a64232335a732666a7783fc04f2319968fff4bfaf7dcc
7
- data.tar.gz: 67fd833bfa126355ef0853263c7e72b5bfa5d013e1061bc128480408a52b49eddf9724686e3dc47293f8713696074f8029452c035159aee50940f0b320ff36ab
6
+ metadata.gz: 15c9fbd5228a60caa7a1d13ec9e6165c1a78ea488a9e7dd992cf60339dfb9523ca8cc68efa0588dddf16f491bf065a878837d943355a7bcae8ba80ec998615d4
7
+ data.tar.gz: aea808fb1eb1ce99c9de4b15c429dc8128d7eee29445a1ca5172498d9f919f8596f28416e2967c41d4bcb6e389e098db90f865e9dce1870229131aaa28212930
data/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## [v3.26.1](https://github.com/bensheldon/good_job/tree/v3.26.1) (2024-03-01)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.26.0...v3.26.1)
6
+
7
+ **Fixed bugs:**
8
+
9
+ - Ignore job deserialization errors when mass-retrying through the dashboard [\#1269](https://github.com/bensheldon/good_job/pull/1269) ([bensheldon](https://github.com/bensheldon))
10
+
11
+ **Closed issues:**
12
+
13
+ - Plain HTTP 500 Error when retrying a job for deleted record [\#1263](https://github.com/bensheldon/good_job/issues/1263)
14
+
15
+ ## [v3.26.0](https://github.com/bensheldon/good_job/tree/v3.26.0) (2024-03-01)
16
+
17
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.25.0...v3.26.0)
18
+
19
+ **Implemented enhancements:**
20
+
21
+ - Add `GoodJob.current_thread_running?` and `GoodJob.current_thread_shutting_down?` for graceful shutdowns [\#1253](https://github.com/bensheldon/good_job/pull/1253) ([bensheldon](https://github.com/bensheldon))
22
+
23
+ **Fixed bugs:**
24
+
25
+ - Ensure "shutdown?" behavior is consistent between J Ruby and C Ruby [\#1267](https://github.com/bensheldon/good_job/pull/1267) ([bensheldon](https://github.com/bensheldon))
26
+
27
+ **Closed issues:**
28
+
29
+ - PG Good Job rows add up [\#1262](https://github.com/bensheldon/good_job/issues/1262)
30
+ - Bulk operations do not work for Batches [\#1255](https://github.com/bensheldon/good_job/issues/1255)
31
+ - What's the difference between 'reschedule' and 'retry' in the dashboard? [\#1241](https://github.com/bensheldon/good_job/issues/1241)
32
+
33
+ **Merged pull requests:**
34
+
35
+ - feat: add italian locale [\#1268](https://github.com/bensheldon/good_job/pull/1268) ([metalelf0](https://github.com/metalelf0))
36
+
3
37
  ## [v3.25.0](https://github.com/bensheldon/good_job/tree/v3.25.0) (2024-02-22)
4
38
 
5
39
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.24.0...v3.25.0)
data/README.md CHANGED
@@ -57,7 +57,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
57
57
  - [Exceptions](#exceptions)
58
58
  - [Retries](#retries)
59
59
  - [Action Mailer retries](#action-mailer-retries)
60
- - [Interrupts](#interrupts)
60
+ - [Interrupts, graceful shutdown, and SIGKILL](#Interrupts-graceful-shutdown-and-SIGKILL)
61
61
  - [Timeouts](#timeouts)
62
62
  - [Optimize queues, threads, and processes](#optimize-queues-threads-and-processes)
63
63
  - [Database connections](#database-connections)
@@ -974,9 +974,24 @@ end
974
974
  Note, that `ActionMailer::MailDeliveryJob` is a default since Rails 6.0. Be sure that your app is using that class, as it
975
975
  might also be configured to use (deprecated now) `ActionMailer::DeliveryJob`.
976
976
 
977
- ### Interrupts
977
+ ### Interrupts, graceful shutdown, and SIGKILL
978
978
 
979
- Jobs will be automatically retried if the process is interrupted while performing a job, for example as the result of a `SIGKILL` or power failure.
979
+ When GoodJob receives an interrupt (SIGINT, SIGTERM) or explicitly with `GoodJob.shutdown`, GoodJob will attempt to gracefully shut down, waiting for all jobs to finish before exiting based on the `shutdown_timeout` configuration.
980
+
981
+ To detect the start of a graceful shutdown from within a performing job, for example while looping/iterating over multiple items, you can call `GoodJob.current_thread_shutting_down?` or `GoodJob.current_thread_running?` from within the job. For example:
982
+
983
+ ```ruby
984
+ def perform(lots_of_records)
985
+ lots_of_records.each do |record|
986
+ break if GoodJob.current_thread_shutting_down? # or `unless GoodJob.current_thread.running?`
987
+ # process record ...
988
+ end
989
+ end
990
+ ````
991
+
992
+ Note that when running jobs in `:inline` execution mode, `GoodJob.current_thread_running?` will always be truthy and `GoodJob.current_thread_shutting_down?` will always be falsey.
993
+
994
+ Jobs will be automatically retried if the process is interrupted while performing a job and the job is unable to finish before the timeout or as the result of a `SIGKILL` or power failure.
980
995
 
981
996
  If you need more control over interrupt-caused retries, include the `GoodJob::ActiveJobExtensions::InterruptErrors` extension in your job class. When an interrupted job is retried, the extension will raise a `GoodJob::InterruptError` exception within the job, which allows you to use Active Job's `retry_on` and `discard_on` to control the behavior of the job.
982
997
 
@@ -44,10 +44,13 @@ module GoodJob
44
44
  end
45
45
 
46
46
  job
47
- rescue GoodJob::Job::ActionForStateMismatchError, GoodJob::AdvisoryLockable::RecordAlreadyAdvisoryLockedError
47
+ rescue GoodJob::Job::ActiveJobDeserializationError,
48
+ GoodJob::Job::ActionForStateMismatchError,
49
+ GoodJob::AdvisoryLockable::RecordAlreadyAdvisoryLockedError
48
50
  nil
49
51
  end.compact
50
52
 
53
+ # TODO: Put these messages through I18n
51
54
  notice = if processed_jobs.any?
52
55
  "Successfully #{ACTIONS[mass_action]} #{processed_jobs.count} #{'job'.pluralize(processed_jobs.count)}"
53
56
  else
@@ -94,11 +97,14 @@ module GoodJob
94
97
  private
95
98
 
96
99
  def redirect_on_error(exception)
100
+ # TODO: Put these messages through I18n
97
101
  alert = case exception
98
102
  when GoodJob::Job::AdapterNotGoodJobError
99
103
  "Active Job Queue Adapter must be GoodJob."
100
104
  when GoodJob::Job::ActionForStateMismatchError
101
105
  "Job is not in an appropriate state for this action."
106
+ when GoodJob::Job::ActiveJobDeserializationError
107
+ "Active Job data could not be deserialized."
102
108
  else
103
109
  exception.to_s
104
110
  end
@@ -104,8 +104,10 @@ module GoodJob
104
104
  def active_job(ignore_deserialization_errors: false)
105
105
  ActiveJob::Base.deserialize(active_job_data).tap do |aj|
106
106
  aj.send(:deserialize_arguments_if_needed)
107
+ rescue ActiveJob::DeserializationError
108
+ raise unless ignore_deserialization_errors
107
109
  end
108
- rescue ActiveJob::DeserializationError, NameError
110
+ rescue NameError
109
111
  raise unless ignore_deserialization_errors
110
112
  end
111
113
 
@@ -13,6 +13,8 @@ module GoodJob
13
13
  AdapterNotGoodJobError = Class.new(StandardError)
14
14
  # Attached to a Job's Execution when the Job is discarded.
15
15
  DiscardJobError = Class.new(StandardError)
16
+ # Raised when Active Job data cannot be deserialized
17
+ ActiveJobDeserializationError = Class.new(StandardError)
16
18
 
17
19
  class << self
18
20
  delegate :table_name, to: GoodJob::Execution
@@ -186,8 +188,9 @@ module GoodJob
186
188
  def retry_job
187
189
  with_advisory_lock do
188
190
  execution = head_execution(reload: true)
189
- active_job = execution.active_job
191
+ active_job = execution.active_job(ignore_deserialization_errors: true)
190
192
 
193
+ raise ActiveJobDeserializationError if active_job.nil?
191
194
  raise AdapterNotGoodJobError unless active_job.class.queue_adapter.is_a? GoodJob::Adapter
192
195
  raise ActionForStateMismatchError if execution.finished_at.blank? || execution.error.blank?
193
196
 
@@ -0,0 +1,243 @@
1
+ ---
2
+ it:
3
+ good_job:
4
+ actions:
5
+ destroy: Elimina
6
+ discard: Scarta
7
+ force_discard: Forza scarto
8
+ inspect: Ispeziona
9
+ reschedule: Riprogramma
10
+ retry: Riprova
11
+ batches:
12
+ index:
13
+ older_batches: Batch più vecchi
14
+ pending_migrations: GoodJob ha migrazioni del database in sospeso.
15
+ title: Batch
16
+ jobs:
17
+ actions:
18
+ confirm_destroy: Sei sicuro di voler eliminare questo job?
19
+ confirm_discard: Sei sicuro di voler scartare questo job?
20
+ confirm_reschedule: Sei sicuro di voler riprogrammare questo job?
21
+ confirm_retry: Sei sicuro di voler riprovare questo job?
22
+ destroy: Elimina job
23
+ discard: Scarta job
24
+ reschedule: Riprogramma job
25
+ retry: Riprova job
26
+ title: Azioni
27
+ no_jobs_found: Nessun job trovato.
28
+ show:
29
+ attributes: Attributi
30
+ batched_jobs: Job raggruppati
31
+ callback_jobs: Job di callback
32
+ table:
33
+ no_batches_found: Nessun batch trovato.
34
+ cron_entries:
35
+ actions:
36
+ confirm_disable: Sei sicuro di voler disabilitare questa voce cron?
37
+ confirm_enable: Sei sicuro di voler confermare questa voce cron?
38
+ confirm_enqueue: Sei sicuro di voler mettere in coda questa voce cron?
39
+ disable: Disabilita voce cron
40
+ enable: Abilita voce cron
41
+ enqueue: Metti in coda voce cron ora
42
+ disable:
43
+ notice: Voce cron è stata disabilitata.
44
+ enable:
45
+ notice: Voce cron è stata abilitata.
46
+ enqueue:
47
+ notice: Voce cron è stata messa in coda.
48
+ index:
49
+ no_cron_schedules_found: Nessuna pianificazione cron trovata.
50
+ title: Pianificazioni cron
51
+ pending_migrations: Richiede migrazione del database GoodJob in sospeso.
52
+ show:
53
+ cron_entry_key: Chiave voce cron
54
+ datetime:
55
+ distance_in_words:
56
+ about_x_hours:
57
+ one: circa 1 ora
58
+ other: circa %{count} ore
59
+ about_x_months:
60
+ one: circa 1 mese
61
+ other: circa %{count} mesi
62
+ about_x_years:
63
+ one: circa 1 anno
64
+ other: circa %{count} anni
65
+ almost_x_years:
66
+ one: quasi 1 anno
67
+ other: quasi %{count} anni
68
+ half_a_minute: mezzo minuto
69
+ less_than_x_minutes:
70
+ one: meno di un minuto
71
+ other: meno di %{count} minuti
72
+ less_than_x_seconds:
73
+ one: meno di 1 secondo
74
+ other: meno di %{count} secondi
75
+ over_x_years:
76
+ one: più di 1 anno
77
+ other: più di %{count} anni
78
+ x_days:
79
+ one: 1 giorno
80
+ other: "%{count} giorni"
81
+ x_minutes:
82
+ one: 1 minuto
83
+ other: "%{count} minuti"
84
+ x_months:
85
+ one: 1 mese
86
+ other: "%{count} mesi"
87
+ x_seconds:
88
+ one: 1 secondo
89
+ other: "%{count} secondi"
90
+ x_years:
91
+ one: 1 anno
92
+ other: "%{count} anni"
93
+ duration:
94
+ hours: "%{hour}h %{min}m"
95
+ less_than_10_seconds: "%{sec}s"
96
+ milliseconds: "%{ms}ms"
97
+ minutes: "%{min}m %{sec}s"
98
+ seconds: "%{sec}s"
99
+ error_event:
100
+ discarded: Scartato
101
+ handled: Gestito
102
+ interrupted: Interrotto
103
+ retried: Riprovato
104
+ retry_stopped: Interrotto riprova
105
+ unhandled: Non gestito
106
+ helpers:
107
+ relative_time:
108
+ future: tra %{time}
109
+ past: "%{time} fa"
110
+ jobs:
111
+ actions:
112
+ confirm_destroy: Sei sicuro di voler eliminare il job?
113
+ confirm_discard: Sei sicuro di voler scartare il job?
114
+ confirm_force_discard: 'Sei sicuro di voler forzare lo scarto di questo job? Il job verrà contrassegnato come scartato ma il job in esecuzione non verrà interrotto - tuttavia, non verrà riprovato in caso di fallimento.
115
+
116
+ '
117
+ confirm_reschedule: Sei sicuro di voler riprogrammare il job?
118
+ confirm_retry: Sei sicuro di voler riprovare il job?
119
+ destroy: Elimina job
120
+ discard: Scarta job
121
+ force_discard: Forza scarto job
122
+ reschedule: Riprogramma job
123
+ retry: Riprova job
124
+ destroy:
125
+ notice: Il job è stato eliminato
126
+ discard:
127
+ notice: Il job è stato scartato
128
+ executions:
129
+ in_queue: in coda
130
+ runtime: tempo di esecuzione
131
+ title: Esecuzioni
132
+ force_discard:
133
+ notice: Il job è stato forzatamente scartato. Continuerà ad eseguirsi ma non verrà riprovato in caso di fallimento
134
+ index:
135
+ job_pagination: Paginazione job
136
+ older_jobs: Job più vecchi
137
+ reschedule:
138
+ notice: Il job è stato riprogrammato
139
+ retry:
140
+ notice: Il job è stato riprovato
141
+ show:
142
+ jobs: Job
143
+ table:
144
+ actions:
145
+ apply_to_all:
146
+ one: Applica al job (1).
147
+ other: Applica a tutti %{count} i job.
148
+ confirm_destroy_all: Sei sicuro di voler eliminare i job selezionati?
149
+ confirm_discard_all: Sei sicuro di voler scartare i job selezionati?
150
+ confirm_reschedule_all: Sei sicuro di voler riprogrammare i job selezionati?
151
+ confirm_retry_all: Sei sicuro di voler riprovare i job selezionati?
152
+ destroy_all: Elimina tutti
153
+ discard_all: Scarta tutti
154
+ reschedule_all: Riprogramma tutti
155
+ retry_all: Riprova tutti
156
+ title: Azioni
157
+ no_jobs_found: Nessun job trovato.
158
+ toggle_actions: Attiva/Disattiva Azioni
159
+ toggle_all_jobs: Attiva/Disattiva tutti i job
160
+ models:
161
+ batch:
162
+ created: Creato
163
+ created_at: Creato il
164
+ discarded: Scartato
165
+ discarded_at: Scartato il
166
+ enqueued: In coda
167
+ enqueued_at: In coda il
168
+ finished: Finito
169
+ finished_at: Finito il
170
+ jobs: Job
171
+ name: Nome
172
+ cron:
173
+ class: Classe
174
+ last_run: Ultima esecuzione
175
+ next_scheduled: Prossima pianificazione
176
+ schedule: Pianificazione
177
+ job:
178
+ arguments: Argomenti
179
+ attempts: Tentativi
180
+ priority: Priorità
181
+ queue: Coda
182
+ number:
183
+ format:
184
+ delimiter: ","
185
+ separator: "."
186
+ human:
187
+ decimal_units:
188
+ delimiter: ","
189
+ format: "%n%u"
190
+ precision: 3
191
+ separator: "."
192
+ units:
193
+ billion: B
194
+ million: M
195
+ quadrillion: Q
196
+ thousand: K
197
+ trillion: T
198
+ unit: ''
199
+ processes:
200
+ index:
201
+ cron_enabled: Cron abilitato
202
+ no_good_job_processes_found: Nessun processo GoodJob trovato.
203
+ process: Processo
204
+ schedulers: Schedulers
205
+ started: Avviato
206
+ title: Processi
207
+ updated: Aggiornato
208
+ shared:
209
+ boolean:
210
+ 'false': 'No'
211
+ 'true': Sì
212
+ error: Errore
213
+ filter:
214
+ all: Tutti
215
+ all_jobs: Tutti i job
216
+ all_queues: Tutte le code
217
+ clear: Cancella
218
+ job_name: Nome job
219
+ placeholder: Cerca per classe, ID job, parametri job e testo errore.
220
+ queue_name: Nome coda
221
+ search: Cerca
222
+ navbar:
223
+ batches: Batch
224
+ cron_schedules: Cron
225
+ jobs: Job
226
+ live_poll: Live Poll
227
+ name: "GoodJob 👍"
228
+ processes: Processi
229
+ theme:
230
+ auto: Auto
231
+ dark: Scuro
232
+ light: Chiaro
233
+ theme: Tema
234
+ secondary_navbar:
235
+ inspiration: Ricorda, stai facendo anche tu un Buon Lavoro!
236
+ last_updated: Ultimo aggiornamento
237
+ status:
238
+ discarded: Scartato
239
+ queued: In coda
240
+ retried: Riprovato
241
+ running: In esecuzione
242
+ scheduled: Pianificato
243
+ succeeded: Riuscito
@@ -78,7 +78,7 @@ module GoodJob
78
78
  # @return [void]
79
79
  def self.reset(values = {})
80
80
  ACCESSORS.each do |accessor|
81
- send("#{accessor}=", values[accessor])
81
+ send(:"#{accessor}=", values[accessor])
82
82
  end
83
83
  end
84
84
 
@@ -93,7 +93,7 @@ module GoodJob # :nodoc:
93
93
  if timeout.nil?
94
94
  @connected.set?
95
95
  else
96
- @connected.wait(timeout == -1 ? nil : timeout)
96
+ @connected.wait(timeout&.negative? ? nil : timeout)
97
97
  end
98
98
  end
99
99
 
@@ -104,7 +104,7 @@ module GoodJob # :nodoc:
104
104
  if timeout.nil?
105
105
  @listening.set?
106
106
  else
107
- @listening.wait(timeout == -1 ? nil : timeout)
107
+ @listening.wait(timeout&.negative? ? nil : timeout)
108
108
  end
109
109
  end
110
110
 
@@ -130,7 +130,7 @@ module GoodJob # :nodoc:
130
130
  @listening.reset
131
131
  @shutdown_event.set
132
132
  else
133
- @shutdown_event.wait(timeout == -1 ? nil : timeout) unless timeout.nil?
133
+ @shutdown_event.wait(timeout&.negative? ? nil : timeout) unless timeout.nil?
134
134
  @connected.reset if @shutdown_event.set?
135
135
  end
136
136
  @shutdown_event.set?
@@ -71,9 +71,11 @@ module GoodJob # :nodoc:
71
71
  # @return [Boolean, nil]
72
72
  delegate :running?, to: :executor, allow_nil: true
73
73
 
74
- # Tests whether the scheduler is shutdown.
74
+ # Tests whether the scheduler is shutdown and no tasks are running.
75
75
  # @return [Boolean, nil]
76
- delegate :shutdown?, to: :executor, allow_nil: true
76
+ def shutdown?
77
+ @executor.nil? || (executor.shutdown? && !executor.shuttingdown?)
78
+ end
77
79
 
78
80
  # Shut down the scheduler.
79
81
  # This stops all threads in the thread pool.
@@ -85,7 +87,7 @@ module GoodJob # :nodoc:
85
87
  # * A positive number will wait that many seconds before stopping any remaining active tasks.
86
88
  # @return [void]
87
89
  def shutdown(timeout: -1)
88
- return if executor.nil? || executor.shutdown?
90
+ return if executor.nil? || (executor.shutdown? && !executor.shuttingdown?)
89
91
 
90
92
  instrument("scheduler_shutdown_start", { timeout: timeout })
91
93
  instrument("scheduler_shutdown", { timeout: timeout }) do
@@ -96,11 +98,11 @@ module GoodJob # :nodoc:
96
98
 
97
99
  if executor.shuttingdown? && timeout
98
100
  executor_wait = timeout.negative? ? nil : timeout
101
+ return if executor.wait_for_termination(executor_wait)
99
102
 
100
- unless executor.wait_for_termination(executor_wait)
101
- instrument("scheduler_shutdown_kill", { active_job_ids: @performer.performing_active_job_ids.to_a })
102
- executor.kill
103
- end
103
+ instrument("scheduler_shutdown_kill", { active_job_ids: @performer.performing_active_job_ids.to_a })
104
+ executor.kill
105
+ executor.wait_for_termination
104
106
  end
105
107
  end
106
108
  end
@@ -268,6 +270,8 @@ module GoodJob # :nodoc:
268
270
  def create_task(delay = 0, fanout: false)
269
271
  future = Concurrent::ScheduledTask.new(delay, args: [self, performer], executor: executor, timer_set: timer_set) do |thr_scheduler, thr_performer|
270
272
  Thread.current.name = Thread.current.name.sub("-worker-", "-thread-") if Thread.current.name
273
+ Thread.current[:good_job_scheduler] = thr_scheduler
274
+
271
275
  Rails.application.reloader.wrap do
272
276
  thr_performer.next do |found|
273
277
  thr_scheduler.create_thread({ fanout: fanout }) if found && fanout
@@ -21,12 +21,10 @@ module GoodJob
21
21
  @executor&.running?
22
22
  end
23
23
 
24
+ # Tests whether the scheduler is shutdown and no tasks are running.
25
+ # @return [Boolean, nil]
24
26
  def shutdown?
25
- if @executor
26
- @executor.shutdown?
27
- else
28
- true
29
- end
27
+ @executor.nil? || (@executor.shutdown? && !@executor.shuttingdown?)
30
28
  end
31
29
 
32
30
  # Shut down the SharedExecutor.
@@ -38,13 +36,16 @@ module GoodJob
38
36
  # * A positive number will wait that many seconds before stopping any remaining active threads.
39
37
  # @return [void]
40
38
  def shutdown(timeout: -1)
41
- return if @executor.nil? || @executor.shutdown?
39
+ return if @executor.nil? || (@executor.shutdown? && !@executor.shuttingdown?)
42
40
 
43
41
  @executor.shutdown if @executor.running?
44
42
 
45
43
  if @executor.shuttingdown? && timeout # rubocop:disable Style/GuardClause
46
44
  executor_wait = timeout.negative? ? nil : timeout
47
- @executor.kill unless @executor.wait_for_termination(executor_wait)
45
+ return if @executor.wait_for_termination(executor_wait)
46
+
47
+ @executor.kill
48
+ @executor.wait_for_termination
48
49
  end
49
50
  end
50
51
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GoodJob
4
+ # Provides methods for determining the status of the
5
+ # current job execution thread. This is useful for determining
6
+ # whether to continue processing a job or to shut down gracefully.
7
+ module ThreadStatus
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ # Whether the current job execution thread is in a running state.
12
+ # @return [Boolean]
13
+ def current_thread_running?
14
+ scheduler = Thread.current[:good_job_scheduler]
15
+ scheduler ? scheduler.running? : true
16
+ end
17
+
18
+ # Whether the current job execution thread is shutting down
19
+ # (the opposite of running).
20
+ # @return [Boolean]
21
+ def current_thread_shutting_down?
22
+ scheduler = Thread.current[:good_job_scheduler]
23
+ scheduler && !scheduler.running?
24
+ end
25
+ end
26
+ end
27
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module GoodJob
4
4
  # GoodJob gem version.
5
- VERSION = '3.25.0'
5
+ VERSION = '3.26.1'
6
6
 
7
7
  # GoodJob version as Gem::Version object
8
8
  GEM_VERSION = Gem::Version.new(VERSION)
data/lib/good_job.rb CHANGED
@@ -40,12 +40,14 @@ require "good_job/probe_server/webrick_handler"
40
40
  require "good_job/scheduler"
41
41
  require "good_job/shared_executor"
42
42
  require "good_job/systemd_service"
43
+ require "good_job/thread_status"
43
44
 
44
45
  # GoodJob is a multithreaded, Postgres-based, ActiveJob backend for Ruby on Rails.
45
46
  #
46
47
  # +GoodJob+ is the top-level namespace and exposes configuration attributes.
47
48
  module GoodJob
48
49
  include GoodJob::Dependencies
50
+ include GoodJob::ThreadStatus
49
51
 
50
52
  # Default, null, blank value placeholder.
51
53
  NONE = Module.new.freeze
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.25.0
4
+ version: 3.26.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-22 00:00:00.000000000 Z
11
+ date: 2024-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -347,6 +347,7 @@ files:
347
347
  - config/locales/en.yml
348
348
  - config/locales/es.yml
349
349
  - config/locales/fr.yml
350
+ - config/locales/it.yml
350
351
  - config/locales/ja.yml
351
352
  - config/locales/ko.yml
352
353
  - config/locales/nl.yml
@@ -407,6 +408,7 @@ files:
407
408
  - lib/good_job/sd_notify.rb
408
409
  - lib/good_job/shared_executor.rb
409
410
  - lib/good_job/systemd_service.rb
411
+ - lib/good_job/thread_status.rb
410
412
  - lib/good_job/version.rb
411
413
  homepage: https://github.com/bensheldon/good_job
412
414
  licenses: