good_job 3.7.4 → 3.8.0

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: fda5fd7d15b1e93616e9dfa44dad4ed89abbad549c5c83d85d3d0fadcb5a3082
4
- data.tar.gz: f114b7657cdd5d1845e9314688c0befaa3c1615df6b203fc6d9cd44e894e7071
3
+ metadata.gz: d5d0c455a8d5d8f18fda38f1f9f126cc406250d188ee313d0352717c829cd126
4
+ data.tar.gz: 208b61ec3b48a7973b160093100b216eafbb96eee604e5e7edc2e7fb67bedfba
5
5
  SHA512:
6
- metadata.gz: d1b5bbbc7f8e407a74d65976996f29df1bea1271a327733a5c685804984c7d5e95d696e3ec823995e856e17e7c22f24edbf7c8425d7caf7ec4795f94f5038357
7
- data.tar.gz: fad2cc50096beae6594326189defab7eec6527e2b2e297518e5c42f220eea3a6201ce7375864b95085ed0462d019da6829e8d34ee02e6ac042968a8f0096a059
6
+ metadata.gz: cac4f2c135e6c01cbdd6cd58c591d726ee8fbb66e623e3d1ed8bfb26e85e6b058e45bd60e3d2ba67b3133666df07d972db8eca75aa05df671b8284c01f45398f
7
+ data.tar.gz: 189ba8af30dc9e5a84c064090d5ede8a8f1da4bb56d2249f6ac4130ce3105c9c498f957ad05cf054f2697f83885570013c3c41ed5d197354c992b08518110656
data/CHANGELOG.md CHANGED
@@ -1,10 +1,41 @@
1
1
  # Changelog
2
2
 
3
+ ## [v3.8.0](https://github.com/bensheldon/good_job/tree/v3.8.0) (2023-01-27)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.7.4...v3.8.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Capture and log ActiveJob IDs that are interrupted when Scheduler is forced to shutdown [\#794](https://github.com/bensheldon/good_job/pull/794) ([bensheldon](https://github.com/bensheldon))
10
+
11
+ **Fixed bugs:**
12
+
13
+ - Ensure Concurrency Keys are string-like and return a better error when they cannot be cast to a string [\#791](https://github.com/bensheldon/good_job/pull/791) ([Earlopain](https://github.com/Earlopain))
14
+
15
+ **Closed issues:**
16
+
17
+ - Work is not being picked up at the expected rate [\#802](https://github.com/bensheldon/good_job/issues/802)
18
+ - Cleaning up preserved jobs only removes a subset of the jobs [\#801](https://github.com/bensheldon/good_job/issues/801)
19
+ - Dashboard fails to execute JS on latest Firefox 108 [\#792](https://github.com/bensheldon/good_job/issues/792)
20
+ - Concurrency key doesn't handle Hash: TypeError \(can't cast Hash\) [\#784](https://github.com/bensheldon/good_job/issues/784)
21
+
22
+ **Merged pull requests:**
23
+
24
+ - Bump fugit from 1.8.0 to 1.8.1 [\#808](https://github.com/bensheldon/good_job/pull/808) ([dependabot[bot]](https://github.com/apps/dependabot))
25
+ - Bump rubocop-rspec from 2.17.1 to 2.18.1 [\#807](https://github.com/bensheldon/good_job/pull/807) ([dependabot[bot]](https://github.com/apps/dependabot))
26
+ - Bump globalid from 1.0.0 to 1.0.1 [\#804](https://github.com/bensheldon/good_job/pull/804) ([dependabot[bot]](https://github.com/apps/dependabot))
27
+ - Bump rack from 2.2.4 to 2.2.6.2 [\#803](https://github.com/bensheldon/good_job/pull/803) ([dependabot[bot]](https://github.com/apps/dependabot))
28
+ - Bump nokogiri from 1.13.10 to 1.14.0 [\#800](https://github.com/bensheldon/good_job/pull/800) ([dependabot[bot]](https://github.com/apps/dependabot))
29
+ - Bump rubocop from 1.42.0 to 1.43.0 [\#799](https://github.com/bensheldon/good_job/pull/799) ([dependabot[bot]](https://github.com/apps/dependabot))
30
+ - Bump rubocop-rspec from 2.16.0 to 2.17.1 [\#798](https://github.com/bensheldon/good_job/pull/798) ([dependabot[bot]](https://github.com/apps/dependabot))
31
+ - Add French translation [\#795](https://github.com/bensheldon/good_job/pull/795) ([francois-ferrandis](https://github.com/francois-ferrandis))
32
+ - Bump rubocop-rails from 2.17.3 to 2.17.4 [\#780](https://github.com/bensheldon/good_job/pull/780) ([dependabot[bot]](https://github.com/apps/dependabot))
33
+
3
34
  ## [v3.7.4](https://github.com/bensheldon/good_job/tree/v3.7.4) (2023-01-10)
4
35
 
5
36
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.7.3...v3.7.4)
6
37
 
7
- **Merged pull requests:**
38
+ **Fixed bugs:**
8
39
 
9
40
  - Update to es-module-shims v1.6.3 and use an inline script entry-point; remove script.js entrypoint; remove sourcemap references [\#793](https://github.com/bensheldon/good_job/pull/793) ([bensheldon](https://github.com/bensheldon))
10
41
 
@@ -80,7 +80,7 @@ module GoodJob
80
80
  def destroy
81
81
  @job = Job.find(params[:id])
82
82
  @job.destroy_job
83
- redirect_to jobs_path, notice: "Job has been destroyed" # rubocop:disable Rails/I18nLocaleTexts
83
+ redirect_to jobs_path, notice: "Job has been destroyed"
84
84
  end
85
85
 
86
86
  private
@@ -212,6 +212,7 @@ module GoodJob
212
212
  break if execution.blank?
213
213
  break :unlocked unless execution&.executable?
214
214
 
215
+ yield(execution) if block_given?
215
216
  result = execution.perform
216
217
  end
217
218
  execution&.run_callbacks(:perform_unlocked)
@@ -193,6 +193,7 @@ module GoodJob
193
193
  binds = [
194
194
  ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
195
195
  ]
196
+
196
197
  locked = connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Lock', binds).first['locked']
197
198
  return locked unless block_given?
198
199
  return nil unless locked
@@ -0,0 +1,83 @@
1
+ ---
2
+ fr:
3
+ datetime:
4
+ distance_in_words:
5
+ about_x_hours:
6
+ one: environ 1 heure
7
+ other: environ %{count} heures
8
+ about_x_months:
9
+ one: environ 1 heure
10
+ other: environ %{count} heures
11
+ about_x_years:
12
+ one: environ 1 an
13
+ other: environ %{count} ans
14
+ almost_x_years:
15
+ one: presque 1 an
16
+ other: presque %{count} ans
17
+ half_a_minute: une demi-minute
18
+ less_than_x_minutes:
19
+ one: moins d'une minute
20
+ other: moins de %{count} minutes
21
+ less_than_x_seconds:
22
+ one: moins d'une seconde
23
+ other: moins de %{count} secondes
24
+ over_x_years:
25
+ one: plus d'un an
26
+ other: plus de %{count} ans
27
+ x_days:
28
+ one: 1 jour
29
+ other: "%{count} jours"
30
+ x_minutes:
31
+ one: 1 minute
32
+ other: "%{count} minutes"
33
+ x_months:
34
+ one: 1 mois
35
+ other: "%{count} mois"
36
+ x_seconds:
37
+ one: 1 seconde
38
+ other: "%{count} secondes"
39
+ x_years:
40
+ one: 1 an
41
+ other: "%{count} ans"
42
+ duration:
43
+ hours: "%{hour}h %{min}m"
44
+ less_than_10_seconds: "%{sec}s"
45
+ milliseconds: "%{ms}ms"
46
+ minutes: "%{min}m %{sec}s"
47
+ seconds: "%{sec}s"
48
+ good_job:
49
+ shared:
50
+ footer:
51
+ last_update_html: Dernière mise à jour <time id="page-updated-at" datetime="%{time}">%{time}</time>
52
+ wording: N'oublie pas, toi aussi tu fais du bon boulot !
53
+ navbar:
54
+ cron_schedules: Cron
55
+ jobs: Jobs
56
+ live_poll: En direct
57
+ name: "GoodJob 👍"
58
+ processes: Processus
59
+ status:
60
+ discarded: Abandonnés
61
+ queued: À la file
62
+ retried: Réessayés
63
+ running: En cours
64
+ scheduled: Programmés
65
+ succeeded: Réussis
66
+ number:
67
+ format:
68
+ delimiter: " "
69
+ separator: ","
70
+ human:
71
+ decimal_units:
72
+ format: "%n%u"
73
+ units:
74
+ billion: B
75
+ million: M
76
+ quadrillion: q
77
+ thousand: k
78
+ trillion: T
79
+ unit: ''
80
+ format:
81
+ delimiter: " "
82
+ precision: 3
83
+ separator: ","
@@ -4,6 +4,8 @@ module GoodJob
4
4
  module Concurrency
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ VALID_TYPES = [String, Symbol, Numeric, Date, Time, TrueClass, FalseClass, NilClass].freeze
8
+
7
9
  class ConcurrencyExceededError < StandardError
8
10
  def backtrace
9
11
  [] # suppress backtrace
@@ -30,6 +32,11 @@ module GoodJob
30
32
  # Always allow jobs to be retried because the current job's execution will complete momentarily
31
33
  next(block.call) if CurrentThread.active_job_id == job.job_id
32
34
 
35
+ # Only generate the concurrency key on the initial enqueue in case it is dynamic
36
+ job.good_job_concurrency_key ||= job._good_job_concurrency_key
37
+ key = job.good_job_concurrency_key
38
+ next(block.call) if key.blank?
39
+
33
40
  enqueue_limit = job.class.good_job_concurrency_config[:enqueue_limit]
34
41
  enqueue_limit = instance_exec(&enqueue_limit) if enqueue_limit.respond_to?(:call)
35
42
  enqueue_limit = nil unless enqueue_limit.present? && (0...Float::INFINITY).cover?(enqueue_limit)
@@ -43,11 +50,6 @@ module GoodJob
43
50
  limit = enqueue_limit || total_limit
44
51
  next(block.call) unless limit
45
52
 
46
- # Only generate the concurrency key on the initial enqueue in case it is dynamic
47
- job.good_job_concurrency_key ||= job._good_job_concurrency_key
48
- key = job.good_job_concurrency_key
49
- next(block.call) if key.blank?
50
-
51
53
  GoodJob::Execution.advisory_lock_key(key, function: "pg_advisory_lock") do
52
54
  enqueue_concurrency = if enqueue_limit
53
55
  GoodJob::Execution.where(concurrency_key: key).unfinished.advisory_unlocked.count
@@ -117,11 +119,10 @@ module GoodJob
117
119
  key = self.class.good_job_concurrency_config[:key]
118
120
  return if key.blank?
119
121
 
120
- if key.respond_to? :call
121
- instance_exec(&key)
122
- else
123
- key
124
- end
122
+ key = key.respond_to?(:call) ? instance_exec(&key) : key
123
+ raise TypeError, "Concurrency key must be a String; was a #{key.class}" unless VALID_TYPES.any? { |type| key.is_a?(type) }
124
+
125
+ key
125
126
  end
126
127
  end
127
128
  end
@@ -10,6 +10,8 @@ module GoodJob
10
10
  # The JobPerformer must be safe to execute across multiple threads.
11
11
  #
12
12
  class JobPerformer
13
+ cattr_accessor :performing_active_job_ids, default: Concurrent::Set.new
14
+
13
15
  # @param queue_string [String] Queues to execute jobs from
14
16
  def initialize(queue_string)
15
17
  @queue_string = queue_string
@@ -24,7 +26,13 @@ module GoodJob
24
26
  # Perform the next eligible job
25
27
  # @return [Object, nil] Returns job result or +nil+ if no job was found
26
28
  def next
27
- job_query.perform_with_advisory_lock(parsed_queues: parsed_queues, queue_select_limit: GoodJob.configuration.queue_select_limit)
29
+ active_job_id = nil
30
+ job_query.perform_with_advisory_lock(parsed_queues: parsed_queues, queue_select_limit: GoodJob.configuration.queue_select_limit) do |execution|
31
+ active_job_id = execution.active_job_id
32
+ performing_active_job_ids << active_job_id
33
+ end
34
+ ensure
35
+ performing_active_job_ids.delete(active_job_id)
28
36
  end
29
37
 
30
38
  # Tests whether this performer should be used in GoodJob's current state.
@@ -85,6 +85,19 @@ module GoodJob
85
85
  end
86
86
  end
87
87
 
88
+ def scheduler_shutdown_kill(event)
89
+ process_id = event.payload[:process_id]
90
+
91
+ warn(tags: [process_id]) do
92
+ active_job_ids = event.payload.fetch(:active_job_ids, [])
93
+ if active_job_ids.any?
94
+ "GoodJob scheduler has been killed. The following Active Jobs were interrupted: #{active_job_ids.join(' ')}"
95
+ else
96
+ "GoodJob scheduler has been killed."
97
+ end
98
+ end
99
+ end
100
+
88
101
  # @!macro notification_responder
89
102
  def scheduler_restart_pools(event)
90
103
  process_id = event.payload[:process_id]
@@ -121,7 +121,11 @@ module GoodJob # :nodoc:
121
121
 
122
122
  if executor.shuttingdown? && timeout
123
123
  executor_wait = timeout.negative? ? nil : timeout
124
- executor.kill unless executor.wait_for_termination(executor_wait)
124
+
125
+ unless executor.wait_for_termination(executor_wait)
126
+ instrument("scheduler_shutdown_kill", { active_job_ids: @performer.performing_active_job_ids.to_a })
127
+ executor.kill
128
+ end
125
129
  end
126
130
  end
127
131
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module GoodJob
3
3
  # GoodJob gem version.
4
- VERSION = '3.7.4'
4
+ VERSION = '3.8.0'
5
5
  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: 3.7.4
4
+ version: 3.8.0
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-01-10 00:00:00.000000000 Z
11
+ date: 2023-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -392,6 +392,7 @@ files:
392
392
  - app/views/layouts/good_job/application.html.erb
393
393
  - config/locales/en.yml
394
394
  - config/locales/es.yml
395
+ - config/locales/fr.yml
395
396
  - config/locales/nl.yml
396
397
  - config/locales/ru.yml
397
398
  - config/locales/ua.yml