good_job 3.4.0 → 3.4.3

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: 73efcb35d2a5e0ccfd13e2526a9a9d4a7195c4bf2e4a7f4127894a68c7f5dbb9
4
- data.tar.gz: d9fddab346e5851e23daa5d9bef8c68b1fd5472f37d687c3cb49c5ff551cc31c
3
+ metadata.gz: 8838f9cf09b7dda04c3dc119db41deef4facc8b31a07e879e082898d77915d8d
4
+ data.tar.gz: a7e146e678ea6432f291f593edfce11497b70201576e299360a026dc83290dda
5
5
  SHA512:
6
- metadata.gz: d720ab703536db9dfd396097aeb8b3aae64f5cd55a1754a9965eaaca275a2babfc4a05d249fb13896d776d02034553bd81cdda8b0af19a6f49d9a3a4bca29045
7
- data.tar.gz: 9dd2af1f00637c3db171934777cc02be231e3ee98ad953aa9fcf030b00faa9fdd2b811f6e69094120a2deee8415e6a33d2d2a4a4d7701fbf89f7c45e272658ef
6
+ metadata.gz: 87a1770d3b74c50c6a40bc63ca50ad368578524029b8d11b5221baf721f7c8169051f0c19bc9554962ff61fc9cf51ac397f042ad393a4c19cecb73924db0c6c2
7
+ data.tar.gz: d707c9b35f41b417628425c74e916c21654992dcb41a27e52fdc88435e74fae09168b85bea81470aeba7eb2236b9d2d57a736ce4c34a5c427c4f82230146d7fa
data/CHANGELOG.md CHANGED
@@ -1,5 +1,54 @@
1
1
  # Changelog
2
2
 
3
+ ## [v3.4.3](https://github.com/bensheldon/good_job/tree/v3.4.3) (2022-08-15)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.4.2...v3.4.3)
6
+
7
+ **Closed issues:**
8
+
9
+ - How to run multiple workers? [\#699](https://github.com/bensheldon/good_job/issues/699)
10
+ - Getting Postgres Errors on killing development server after setting up Goodjob [\#692](https://github.com/bensheldon/good_job/issues/692)
11
+
12
+ **Merged pull requests:**
13
+
14
+ - Fix Project v2 GitHub Actions [\#701](https://github.com/bensheldon/good_job/pull/701) ([bensheldon](https://github.com/bensheldon))
15
+ - Remove development dependencies: memory\_profiler, rbtrace, sigdump [\#700](https://github.com/bensheldon/good_job/pull/700) ([bensheldon](https://github.com/bensheldon))
16
+ - Allow concurrency limits to be configured dynamically with lambda/proc [\#696](https://github.com/bensheldon/good_job/pull/696) ([baka-san](https://github.com/baka-san))
17
+ - Add additional details to Concurrency Control explanation [\#695](https://github.com/bensheldon/good_job/pull/695) ([bensheldon](https://github.com/bensheldon))
18
+
19
+ ## [v3.4.2](https://github.com/bensheldon/good_job/tree/v3.4.2) (2022-08-13)
20
+
21
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.4.1...v3.4.2)
22
+
23
+ **Fixed bugs:**
24
+
25
+ - Jobs enqueued via dashboard ignores app default\_locale [\#697](https://github.com/bensheldon/good_job/issues/697)
26
+ - Include better exception log messages, including class and backtrace [\#693](https://github.com/bensheldon/good_job/pull/693) ([bensheldon](https://github.com/bensheldon))
27
+
28
+ **Closed issues:**
29
+
30
+ - Do we need to implement concurrency with scheduled cron jobs? [\#690](https://github.com/bensheldon/good_job/issues/690)
31
+ - Uninitialized constant GoodJob::JobsController [\#674](https://github.com/bensheldon/good_job/issues/674)
32
+ - ActiveRecord::StatementInvalid: PG::ConnectionBad: PQsocket\(\) can't get socket descriptor every 30 minutes aprox. [\#579](https://github.com/bensheldon/good_job/issues/579)
33
+ - Handle assets in dashboard when rails app is behind proxy path [\#424](https://github.com/bensheldon/good_job/issues/424)
34
+
35
+ **Merged pull requests:**
36
+
37
+ - Enqueues Cron jobs with I18n default locale [\#698](https://github.com/bensheldon/good_job/pull/698) ([esasse](https://github.com/esasse))
38
+
39
+ ## [v3.4.1](https://github.com/bensheldon/good_job/tree/v3.4.1) (2022-08-06)
40
+
41
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.4.0...v3.4.1)
42
+
43
+ **Closed issues:**
44
+
45
+ - Add `cron_enabled` to Process state [\#673](https://github.com/bensheldon/good_job/issues/673)
46
+ - Good job is using a lot of memory / ram [\#613](https://github.com/bensheldon/good_job/issues/613)
47
+
48
+ **Merged pull requests:**
49
+
50
+ - Only report Notifier connection errors once after they happen 3 consecutive times [\#689](https://github.com/bensheldon/good_job/pull/689) ([bensheldon](https://github.com/bensheldon))
51
+
3
52
  ## [v3.4.0](https://github.com/bensheldon/good_job/tree/v3.4.0) (2022-08-05)
4
53
 
5
54
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.3.3...v3.4.0)
data/README.md CHANGED
@@ -406,15 +406,18 @@ class MyJob < ApplicationJob
406
406
 
407
407
  good_job_control_concurrency_with(
408
408
  # Maximum number of unfinished jobs to allow with the concurrency key
409
+ # Can be an Integer or Lambda/Proc that is invoked in the context of the job
409
410
  total_limit: 1,
410
411
 
411
412
  # Or, if more control is needed:
412
413
  # Maximum number of jobs with the concurrency key to be
413
414
  # concurrently enqueued (excludes performing jobs)
415
+ # Can be an Integer or Lambda/Proc that is invoked in the context of the job
414
416
  enqueue_limit: 2,
415
417
 
416
418
  # Maximum number of jobs with the concurrency key to be
417
419
  # concurrently performed (excludes enqueued jobs)
420
+ # Can be an Integer or Lambda/Proc that is invoked in the context of the job
418
421
  perform_limit: 1,
419
422
 
420
423
  # Note: Under heavy load, the total number of jobs may exceed the
@@ -444,10 +447,11 @@ job.good_job_concurrency_key #=> "Unique-Alice"
444
447
 
445
448
  #### How concurrency controls work
446
449
 
447
- GoodJob's concurrency control strategy for `perform_limit` is "optimistic retry with an incremental backoff". The [code is readable](https://github.com/bensheldon/good_job/blob/main/lib/good_job/active_job_extensions/concurrency.rb).
450
+ GoodJob's concurrency control strategy for `perform_limit` is "optimistic retry with an incremental backoff". The [code is readable](https://github.com/bensheldon/good_job/blob/main/lib/good_job/active_job_extensions/concurrency.rb).
448
451
 
449
- - "Optimistic" meaning that the implementation's performance trade-off assumes that collisions are atypical (e.g. two users enqueue the same job at the same time) rather than regular (e.g. the system enqueues thousands of colliding jobs at the same time).
452
+ - "Optimistic" meaning that the implementation's performance trade-off assumes that collisions are atypical (e.g. two users enqueue the same job at the same time) rather than regular (e.g. the system enqueues thousands of colliding jobs at the same time). Depending on your concurrency requirements, you may also want to manage concurrency through the number of GoodJob threads and processes that are performing a given queue.
450
453
  - "Retry with an incremental backoff" means that when `perform_limit` is exceeded, the job will raise a `GoodJob::ActiveJobExtensions::Concurrency::ConcurrencyExceededError` which is caught by a `retry_on` handler which re-schedules the job to execute in the near future with an incremental backoff.
454
+ - First-in-first-out job execution order is not preserved when a job is retried with incremental back-off.
451
455
 
452
456
  ### Cron-style repeating/recurring jobs
453
457
 
@@ -106,7 +106,9 @@ module GoodJob # :nodoc:
106
106
  current_thread.cron_at = cron_at
107
107
 
108
108
  configured_job = job_class.constantize.set(set_value)
109
- kwargs_value.present? ? configured_job.perform_later(*args_value, **kwargs_value) : configured_job.perform_later(*args_value)
109
+ I18n.with_locale(I18n.default_locale) do
110
+ kwargs_value.present? ? configured_job.perform_later(*args_value, **kwargs_value) : configured_job.perform_later(*args_value)
111
+ end
110
112
  end
111
113
  rescue ActiveRecord::RecordNotUnique
112
114
  false
@@ -31,11 +31,17 @@ module GoodJob
31
31
  next(block.call) if CurrentThread.active_job_id == job.job_id
32
32
 
33
33
  enqueue_limit = job.class.good_job_concurrency_config[:enqueue_limit]
34
- total_limit = job.class.good_job_concurrency_config[:total_limit]
34
+ enqueue_limit = instance_exec(&enqueue_limit) if enqueue_limit.respond_to?(:call)
35
+ enqueue_limit = nil unless enqueue_limit.present? && (0...Float::INFINITY).cover?(enqueue_limit)
35
36
 
36
- has_limit = (enqueue_limit.present? && (0...Float::INFINITY).cover?(enqueue_limit)) ||
37
- (total_limit.present? && (0...Float::INFINITY).cover?(total_limit))
38
- next(block.call) unless has_limit
37
+ unless enqueue_limit
38
+ total_limit = job.class.good_job_concurrency_config[:total_limit]
39
+ total_limit = instance_exec(&total_limit) if total_limit.respond_to?(:call)
40
+ total_limit = nil unless total_limit.present? && (0...Float::INFINITY).cover?(total_limit)
41
+ end
42
+
43
+ limit = enqueue_limit || total_limit
44
+ next(block.call) unless limit
39
45
 
40
46
  # Only generate the concurrency key on the initial enqueue in case it is dynamic
41
47
  job.good_job_concurrency_key ||= job._good_job_concurrency_key
@@ -50,7 +56,7 @@ module GoodJob
50
56
  end
51
57
 
52
58
  # The job has not yet been enqueued, so check if adding it will go over the limit
53
- block.call unless enqueue_concurrency + 1 > (enqueue_limit || total_limit)
59
+ block.call unless (enqueue_concurrency + 1) > limit
54
60
  end
55
61
  end
56
62
 
@@ -64,11 +70,18 @@ module GoodJob
64
70
  # Don't attempt to enforce concurrency limits with other queue adapters.
65
71
  next unless job.class.queue_adapter.is_a?(GoodJob::Adapter)
66
72
 
67
- perform_limit = job.class.good_job_concurrency_config[:perform_limit] ||
68
- job.class.good_job_concurrency_config[:total_limit]
73
+ perform_limit = job.class.good_job_concurrency_config[:perform_limit]
74
+ perform_limit = instance_exec(&perform_limit) if perform_limit.respond_to?(:call)
75
+ perform_limit = nil unless perform_limit.present? && (0...Float::INFINITY).cover?(perform_limit)
76
+
77
+ unless perform_limit
78
+ total_limit = job.class.good_job_concurrency_config[:total_limit]
79
+ total_limit = instance_exec(&total_limit) if total_limit.respond_to?(:call)
80
+ total_limit = nil unless total_limit.present? && (0...Float::INFINITY).cover?(total_limit)
81
+ end
69
82
 
70
- has_limit = perform_limit.present? && (0...Float::INFINITY).cover?(perform_limit)
71
- next unless has_limit
83
+ limit = perform_limit || total_limit
84
+ next unless limit
72
85
 
73
86
  key = job.good_job_concurrency_key
74
87
  next if key.blank?
@@ -79,7 +92,7 @@ module GoodJob
79
92
  end
80
93
 
81
94
  GoodJob::Execution.advisory_lock_key(key, function: "pg_advisory_lock") do
82
- allowed_active_job_ids = GoodJob::Execution.unfinished.where(concurrency_key: key).advisory_locked.order(Arel.sql("COALESCE(performed_at, scheduled_at, created_at) ASC")).limit(perform_limit).pluck(:active_job_id)
95
+ allowed_active_job_ids = GoodJob::Execution.unfinished.where(concurrency_key: key).advisory_locked.order(Arel.sql("COALESCE(performed_at, scheduled_at, created_at) ASC")).limit(limit).pluck(:active_job_id)
83
96
  # The current job has already been locked and will appear in the previous query
84
97
  raise GoodJob::ActiveJobExtensions::Concurrency::ConcurrencyExceededError unless allowed_active_job_ids.include? job.job_id
85
98
  end
@@ -32,7 +32,7 @@ module GoodJob
32
32
  return unless exception
33
33
 
34
34
  error do
35
- "GoodJob error: #{exception}\n #{exception.backtrace}"
35
+ "GoodJob error: #{exception.class}: #{exception}\n #{exception.backtrace}"
36
36
  end
37
37
  end
38
38
 
@@ -42,7 +42,7 @@ module GoodJob
42
42
  return unless exception
43
43
 
44
44
  error do
45
- "GoodJob error: #{exception}\n #{exception.backtrace}"
45
+ "GoodJob error: #{exception.class}: #{exception}\n #{exception.backtrace}"
46
46
  end
47
47
  end
48
48
 
@@ -123,10 +123,10 @@ module GoodJob
123
123
 
124
124
  # @!macro notification_responder
125
125
  def notifier_notify_error(event)
126
- error = event.payload[:error]
126
+ exception = event.payload[:error]
127
127
 
128
128
  error do
129
- "Notifier errored: #{error}"
129
+ "Notifier errored: #{exception.class}: #{exception}\n #{exception.backtrace}"
130
130
  end
131
131
  end
132
132
 
@@ -40,6 +40,7 @@ module GoodJob # :nodoc:
40
40
  PG::UnableToSend
41
41
  PG::Error
42
42
  ].freeze
43
+ CONNECTION_ERRORS_REPORTING_THRESHOLD = 3
43
44
 
44
45
  # @!attribute [r] instances
45
46
  # @!scope class
@@ -70,6 +71,8 @@ module GoodJob # :nodoc:
70
71
  def initialize(*recipients)
71
72
  @recipients = Concurrent::Array.new(recipients)
72
73
  @listening = Concurrent::AtomicBoolean.new(false)
74
+ @connection_errors_count = Concurrent::AtomicFixnum.new(0)
75
+ @connection_errors_reported = Concurrent::AtomicBoolean.new(false)
73
76
 
74
77
  self.class.instances << self
75
78
 
@@ -128,7 +131,6 @@ module GoodJob # :nodoc:
128
131
  # @return [void]
129
132
  def listen_observer(_time, _result, thread_error)
130
133
  if thread_error
131
- GoodJob._on_thread_error(thread_error)
132
134
  ActiveSupport::Notifications.instrument("notifier_notify_error.good_job", { error: thread_error })
133
135
 
134
136
  connection_error = CONNECTION_ERRORS.any? do |error_string|
@@ -137,6 +139,16 @@ module GoodJob # :nodoc:
137
139
 
138
140
  thread_error.is_a? error_class
139
141
  end
142
+
143
+ if connection_error
144
+ @connection_errors_count.increment
145
+ if @connection_errors_reported.false? && @connection_errors_count.value >= CONNECTION_ERRORS_REPORTING_THRESHOLD
146
+ GoodJob._on_thread_error(thread_error)
147
+ @connection_errors_reported.make_true
148
+ end
149
+ else
150
+ GoodJob._on_thread_error(thread_error)
151
+ end
140
152
  end
141
153
 
142
154
  return if shutdown?
@@ -175,6 +187,8 @@ module GoodJob # :nodoc:
175
187
  target.send(method_name, parsed_payload)
176
188
  end
177
189
  end
190
+
191
+ reset_connection_errors
178
192
  end
179
193
  end
180
194
  end
@@ -223,5 +237,10 @@ module GoodJob # :nodoc:
223
237
  sleep WAIT_INTERVAL
224
238
  end
225
239
  end
240
+
241
+ def reset_connection_errors
242
+ @connection_errors_count.value = 0
243
+ @connection_errors_reported.make_false
244
+ end
226
245
  end
227
246
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module GoodJob
3
3
  # GoodJob gem version.
4
- VERSION = '3.4.0'
4
+ VERSION = '3.4.3'
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.4.0
4
+ version: 3.4.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: 2022-08-05 00:00:00.000000000 Z
11
+ date: 2022-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -290,20 +290,6 @@ dependencies:
290
290
  - - ">="
291
291
  - !ruby/object:Gem::Version
292
292
  version: '0'
293
- - !ruby/object:Gem::Dependency
294
- name: sigdump
295
- requirement: !ruby/object:Gem::Requirement
296
- requirements:
297
- - - ">="
298
- - !ruby/object:Gem::Version
299
- version: '0'
300
- type: :development
301
- prerelease: false
302
- version_requirements: !ruby/object:Gem::Requirement
303
- requirements:
304
- - - ">="
305
- - !ruby/object:Gem::Version
306
- version: '0'
307
293
  - !ruby/object:Gem::Dependency
308
294
  name: yard
309
295
  requirement: !ruby/object:Gem::Requirement