good_job 2.7.1 → 2.7.2

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: ad8ca019c816dee452b246cdaa6d806844bcbd6aca63da6e5d52c87828c9c8e4
4
- data.tar.gz: 343c128a0d8477688e8f38d214add4c341dbfce694c19c6c2acf9cf7bb5c5cef
3
+ metadata.gz: e4843101f6fce50527e8d0157ff7ced91fabb0ae41c3c92006abd49e9005ea78
4
+ data.tar.gz: f8f243fb7f9e3ea2ec17fc795ad5bbd79b017f68665d98b911dfe27177e13389
5
5
  SHA512:
6
- metadata.gz: d5153a01609aefefd4ac23319ba76755ba13ea64c749b9b582fda5a17a497c0d640e20e6db91aa9eb9b18042b62283acc8dd25c67f1389290291ae55c2187f33
7
- data.tar.gz: e145b2a1d26eaf4b07e60ca8826e39216de230569f197f0eafae481b7716754aeb95a4bce54330e15389612f49361f320c8934965beca9c4c60d97f1a84f3b05
6
+ metadata.gz: f2dbdd1c1811bfc09153a8eed32b95f337919d22434b004622a0ab78eb6803e68f5a66761e828bf2054421d5d5f9b798be54e7f60cc486602a997c804ab9fb2d
7
+ data.tar.gz: 953672a066c27a231fb76c3c9839b4cb9685deb0ed4f25a3e153f4ede0833afa0a263f4d37532715a62ed7a96825384b8f7d6fef7352416d0c64068864798fee
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [v2.7.2](https://github.com/bensheldon/good_job/tree/v2.7.2) (2021-11-29)
4
+
5
+ [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.7.1...v2.7.2)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Allow GoodJob global configuration accessors to also be set via Rails config hash [\#460](https://github.com/bensheldon/good_job/pull/460) ([bensheldon](https://github.com/bensheldon))
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Use `ActiveRecord::Relation::QueryAttribute` when setting up bindings for `exec_query` [\#461](https://github.com/bensheldon/good_job/pull/461) ([bensheldon](https://github.com/bensheldon))
14
+ - Configure RSpec `config.example_status_persistence_file_path` [\#459](https://github.com/bensheldon/good_job/pull/459) ([bensheldon](https://github.com/bensheldon))
15
+ - Defer async initialization until Rails fully initialized [\#454](https://github.com/bensheldon/good_job/pull/454) ([bensheldon](https://github.com/bensheldon))
16
+
3
17
  ## [v2.7.1](https://github.com/bensheldon/good_job/tree/v2.7.1) (2021-11-26)
4
18
 
5
19
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v2.7.0...v2.7.1)
data/README.md CHANGED
@@ -97,7 +97,7 @@ For more of the story of GoodJob, read the [introductory blog post](https://isla
97
97
  1. Configure the ActiveJob adapter:
98
98
 
99
99
  ```ruby
100
- # config/application.rb
100
+ # config/application.rb or config/environments/{RAILS_ENV}.rb
101
101
  config.active_job.queue_adapter = :good_job
102
102
  ```
103
103
 
@@ -212,43 +212,48 @@ to delete old records and preserve space in your database.
212
212
 
213
213
  ### Configuration options
214
214
 
215
- To use GoodJob, you can set `config.active_job.queue_adapter` to a `:good_job`.
215
+ ActiveJob configuration depends on where the code is placed:
216
216
 
217
- Additional configuration can be provided via `config.good_job.OPTION = ...`.
217
+ - `config.active_job.queue_adapter = :good_job` within `config/application.rb` or `config/environments/*.rb`.
218
+ - `ActiveJob::Base.queue_adapter = :good_job` within an initializer (e.g. `config/initializers/active_job.rb`).
218
219
 
219
- _Configuration **must** be placed into `config/application.rb` or `config/environments/{RAILS_ENV}.rb`; configuration may not work correctly if placed into `config/initializers/*.rb` because application initializers run _after_ gem initialization (see [Rails#36650](https://github.com/rails/rails/issues/36650) and [GoodJob#380](https://github.com/bensheldon/good_job/issues/380))._
220
+ GoodJob configuration can be placed within Rails `config` directory for all environments (`config/application.rb`), within a particular environment (e.g. `config/environments/development.rb`), or within an initializer (e.g. `config/initializers/good_job.rb`).
220
221
 
221
222
  Configuration examples:
222
223
 
223
224
  ```ruby
224
- # config/application.rb
225
-
226
- config.active_job.queue_adapter = :good_job
227
-
228
- # Configure options individually...
229
- config.good_job.execution_mode = :async
230
- config.good_job.max_threads = 5
231
- config.good_job.poll_interval = 30 # seconds
232
- config.good_job.shutdown_timeout = 25 # seconds
233
- config.good_job.enable_cron = true
234
- config.good_job.cron = { example: { cron: '0 * * * *', class: 'ExampleJob' } }
235
- config.good_job.queues = '*'
236
-
237
- # ...or all at once.
238
- config.good_job = {
239
- execution_mode: :async,
240
- max_threads: 5,
241
- poll_interval: 30,
242
- shutdown_timeout: 25,
243
- enable_cron: true,
244
- cron: {
245
- example: {
246
- cron: '0 * * * *',
247
- class: 'ExampleJob'
225
+ Rails.application.configure do
226
+ # Configure options individually...
227
+ config.good_job.preserve_job_records = true
228
+ config.good_job.retry_on_unhandled_error = false
229
+ config.good_job.on_thread_error = -> (exception) { Raven.capture_exception(exception) }
230
+ config.good_job.execution_mode = :async
231
+ config.good_job.max_threads = 5
232
+ config.good_job.poll_interval = 30 # seconds
233
+ config.good_job.shutdown_timeout = 25 # seconds
234
+ config.good_job.enable_cron = true
235
+ config.good_job.cron = { example: { cron: '0 * * * *', class: 'ExampleJob' } }
236
+ config.good_job.queues = '*'
237
+
238
+ # ...or all at once.
239
+ config.good_job = {
240
+ preserve_job_records: true,
241
+ retry_on_unhandled_error: false,
242
+ on_thread_error: -> (exception) { Raven.capture_exception(exception) },
243
+ execution_mode: :async,
244
+ max_threads: 5,
245
+ poll_interval: 30,
246
+ shutdown_timeout: 25,
247
+ enable_cron: true,
248
+ cron: {
249
+ example: {
250
+ cron: '0 * * * *',
251
+ class: 'ExampleJob'
252
+ },
248
253
  },
249
- },
250
- queues: '*',
251
- }
254
+ queues: '*',
255
+ }
256
+ end
252
257
  ```
253
258
 
254
259
  Available configuration options are:
@@ -265,6 +270,14 @@ Available configuration options are:
265
270
  - `shutdown_timeout` (float) number of seconds to wait for jobs to finish when shutting down before stopping the thread. Defaults to forever: `-1`. You can also set this with the environment variable `GOOD_JOB_SHUTDOWN_TIMEOUT`.
266
271
  - `enable_cron` (boolean) whether to run cron process. Defaults to `false`. You can also set this with the environment variable `GOOD_JOB_ENABLE_CRON`.
267
272
  - `cron` (hash) cron configuration. Defaults to `{}`. You can also set this as a JSON string with the environment variable `GOOD_JOB_CRON`
273
+ - `logger` ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger` (Default: `Rails.logger`).
274
+ - `preserve_job_records` (boolean) keeps job records in your database even after jobs are completed. (Default: `false`)
275
+ - `retry_on_unhandled_error` (boolean) causes jobs to be re-queued and retried if they raise an instance of `StandardError`. Instances of `Exception`, like SIGINT, will *always* be retried, regardless of this attribute’s value. (Default: `true`)
276
+ - `on_thread_error` (proc, lambda, or callable) will be called when an Exception. It can be useful for logging errors to bug tracking services, like Sentry or Airbrake. Example:
277
+
278
+ ```ruby
279
+ config.good_job.on_thread_error = -> (exception) { Raven.capture_exception(exception) }
280
+ ```
268
281
 
269
282
  By default, GoodJob configures the following execution modes per environment:
270
283
 
@@ -285,7 +298,7 @@ config.good_job.execution_mode = :external
285
298
 
286
299
  ### Global options
287
300
 
288
- Good Job’s general behavior can also be configured via several attributes directly on the `GoodJob` module:
301
+ Good Job’s general behavior can also be configured via attributes directly on the `GoodJob` module:
289
302
 
290
303
  - **`GoodJob.active_record_parent_class`** (string) The ActiveRecord parent class inherited by GoodJob's ActiveRecord model `GoodJob::Job` (defaults to `"ActiveRecord::Base"`). Configure this when using [multiple databases with ActiveRecord](https://guides.rubyonrails.org/active_record_multiple_databases.html) or when other custom configuration is necessary for the ActiveRecord model to connect to the Postgres database. _The value must be a String to avoid premature initialization of ActiveRecord._
291
304
  - **`GoodJob.logger`** ([Rails Logger](https://api.rubyonrails.org/classes/ActiveSupport/Logger.html)) lets you set a custom logger for GoodJob. It should be an instance of a Rails `Logger`.
@@ -30,7 +30,10 @@ module GoodJob
30
30
  ORDER BY timestamp ASC
31
31
  SQL
32
32
 
33
- binds = [[nil, start_time], [nil, end_time]]
33
+ binds = [
34
+ ActiveRecord::Relation::QueryAttribute.new('start_time', start_time, ActiveRecord::Type::DateTime.new),
35
+ ActiveRecord::Relation::QueryAttribute.new('end_time', end_time, ActiveRecord::Type::DateTime.new),
36
+ ]
34
37
  executions_data = GoodJob::Execution.connection.exec_query(GoodJob::Execution.pg_or_jdbc_query(count_query), "GoodJob Dashboard Chart", binds)
35
38
 
36
39
  queue_names = executions_data.reject { |d| d['count'].nil? }.map { |d| d['queue_name'] || BaseFilter::EMPTY }.uniq
@@ -4,6 +4,12 @@ module GoodJob
4
4
  # ActiveJob Adapter.
5
5
  #
6
6
  class Adapter
7
+ # @!attribute [r] instances
8
+ # @!scope class
9
+ # List of all instantiated Adapters in the current process.
10
+ # @return [Array<GoodJob::Adapter>, nil]
11
+ cattr_reader :instances, default: [], instance_reader: false
12
+
7
13
  # @param execution_mode [Symbol, nil] specifies how and where jobs should be executed. You can also set this with the environment variable +GOOD_JOB_EXECUTION_MODE+.
8
14
  #
9
15
  # - +:inline+ executes jobs immediately in whatever process queued them (usually the web server process). This should only be used in test and development environments.
@@ -20,7 +26,8 @@ module GoodJob
20
26
  # @param max_threads [Integer, nil] sets the number of threads per scheduler to use when +execution_mode+ is set to +:async+. The +queues+ parameter can specify a number of threads for each group of queues which will override this value. You can also set this with the environment variable +GOOD_JOB_MAX_THREADS+. Defaults to +5+.
21
27
  # @param queues [String, nil] determines which queues to execute jobs from when +execution_mode+ is set to +:async+. See {file:README.md#optimize-queues-threads-and-processes} for more details on the format of this string. You can also set this with the environment variable +GOOD_JOB_QUEUES+. Defaults to +"*"+.
22
28
  # @param poll_interval [Integer, nil] sets the number of seconds between polls for jobs when +execution_mode+ is set to +:async+. You can also set this with the environment variable +GOOD_JOB_POLL_INTERVAL+. Defaults to +1+.
23
- def initialize(execution_mode: nil, queues: nil, max_threads: nil, poll_interval: nil)
29
+ # @param start_async_on_initialize [Boolean] whether to start the async scheduler when the adapter is initialized.
30
+ def initialize(execution_mode: nil, queues: nil, max_threads: nil, poll_interval: nil, start_async_on_initialize: Rails.application.initialized?)
24
31
  @configuration = GoodJob::Configuration.new(
25
32
  {
26
33
  execution_mode: execution_mode,
@@ -30,16 +37,9 @@ module GoodJob
30
37
  }
31
38
  )
32
39
  @configuration.validate!
40
+ self.class.instances << self
33
41
 
34
- if execute_async? # rubocop:disable Style/GuardClause
35
- @notifier = GoodJob::Notifier.new
36
- @poller = GoodJob::Poller.new(poll_interval: @configuration.poll_interval)
37
- @scheduler = GoodJob::Scheduler.from_configuration(@configuration, warm_cache_on_initialize: Rails.application.initialized?)
38
- @notifier.recipients << [@scheduler, :create_thread]
39
- @poller.recipients << [@scheduler, :create_thread]
40
-
41
- @cron_manager = GoodJob::CronManager.new(@configuration.cron_entries, start_on_initialize: Rails.application.initialized?) if @configuration.enable_cron?
42
- end
42
+ start_async if start_async_on_initialize
43
43
  end
44
44
 
45
45
  # Enqueues the ActiveJob job to be performed.
@@ -74,7 +74,7 @@ module GoodJob
74
74
  job_state = { queue_name: execution.queue_name }
75
75
  job_state[:scheduled_at] = execution.scheduled_at if execution.scheduled_at
76
76
 
77
- executed_locally = execute_async? && @scheduler.create_thread(job_state)
77
+ executed_locally = execute_async? && @scheduler&.create_thread(job_state)
78
78
  Notifier.notify(job_state) unless executed_locally
79
79
  end
80
80
 
@@ -97,6 +97,7 @@ module GoodJob
97
97
 
98
98
  executables = [@notifier, @poller, @scheduler].compact
99
99
  GoodJob._shutdown_all(executables, timeout: timeout)
100
+ @_async_started = false
100
101
  end
101
102
 
102
103
  # Whether in +:async+ execution mode.
@@ -119,6 +120,28 @@ module GoodJob
119
120
  @configuration.execution_mode == :inline
120
121
  end
121
122
 
123
+ # Start async executors
124
+ # @return void
125
+ def start_async
126
+ return unless execute_async?
127
+
128
+ @notifier = GoodJob::Notifier.new
129
+ @poller = GoodJob::Poller.new(poll_interval: @configuration.poll_interval)
130
+ @scheduler = GoodJob::Scheduler.from_configuration(@configuration, warm_cache_on_initialize: true)
131
+ @notifier.recipients << [@scheduler, :create_thread]
132
+ @poller.recipients << [@scheduler, :create_thread]
133
+
134
+ @cron_manager = GoodJob::CronManager.new(@configuration.cron_entries, start_on_initialize: true) if @configuration.enable_cron?
135
+
136
+ @_async_started = true
137
+ end
138
+
139
+ # Whether the async executors are running
140
+ # @return [Boolean]
141
+ def async_started?
142
+ @_async_started
143
+ end
144
+
122
145
  private
123
146
 
124
147
  # Whether running in a web server process.
data/lib/good_job/cli.rb CHANGED
@@ -96,6 +96,7 @@ module GoodJob
96
96
  poller.recipients << [scheduler, :create_thread]
97
97
 
98
98
  cron_manager = GoodJob::CronManager.new(configuration.cron_entries, start_on_initialize: true) if configuration.enable_cron?
99
+
99
100
  if configuration.probe_port
100
101
  probe_server = GoodJob::ProbeServer.new(port: configuration.probe_port)
101
102
  probe_server.start
@@ -50,24 +50,22 @@ module GoodJob
50
50
  # for more details on possible values.
51
51
  # @return [Symbol]
52
52
  def execution_mode
53
- @_execution_mode ||= begin
54
- mode = if GoodJob::CLI.within_exe?
55
- :external
56
- else
57
- options[:execution_mode] ||
58
- rails_config[:execution_mode] ||
59
- env['GOOD_JOB_EXECUTION_MODE']
60
- end
61
-
62
- if mode
63
- mode.to_sym
64
- elsif Rails.env.development?
65
- :async
66
- elsif Rails.env.test?
67
- :inline
68
- else
69
- :external
70
- end
53
+ mode = if GoodJob::CLI.within_exe?
54
+ :external
55
+ else
56
+ options[:execution_mode] ||
57
+ rails_config[:execution_mode] ||
58
+ env['GOOD_JOB_EXECUTION_MODE']
59
+ end
60
+
61
+ if mode
62
+ mode.to_sym
63
+ elsif Rails.env.development?
64
+ :async
65
+ elsif Rails.env.test?
66
+ :inline
67
+ else
68
+ :external
71
69
  end
72
70
  end
73
71
 
@@ -21,7 +21,7 @@ module GoodJob # :nodoc:
21
21
  def self.task_observer(time, output, thread_error) # rubocop:disable Lint/UnusedMethodArgument
22
22
  return if thread_error.is_a? Concurrent::CancelledOperationError
23
23
 
24
- GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
24
+ GoodJob._on_thread_error(thread_error) if thread_error
25
25
  end
26
26
 
27
27
  # Execution configuration to be scheduled
@@ -215,7 +215,9 @@ module GoodJob
215
215
  SQL
216
216
  end
217
217
 
218
- binds = [[nil, key]]
218
+ binds = [
219
+ ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
220
+ ]
219
221
  self.class.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Lock', binds).first['locked']
220
222
  end
221
223
 
@@ -229,7 +231,9 @@ module GoodJob
229
231
  query = <<~SQL.squish
230
232
  SELECT #{function}(('x'||substr(md5($1::text), 1, 16))::bit(64)::bigint) AS unlocked
231
233
  SQL
232
- binds = [[nil, key]]
234
+ binds = [
235
+ ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
236
+ ]
233
237
  self.class.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Unlock', binds).first['unlocked']
234
238
  end
235
239
 
@@ -279,7 +283,10 @@ module GoodJob
279
283
  AND pg_locks.classid = ('x' || substr(md5($1::text), 1, 16))::bit(32)::int
280
284
  AND pg_locks.objid = (('x' || substr(md5($2::text), 1, 16))::bit(64) << 32)::bit(32)::int
281
285
  SQL
282
- binds = [[nil, key], [nil, key]]
286
+ binds = [
287
+ ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
288
+ ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
289
+ ]
283
290
  self.class.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Locked?', binds).any?
284
291
  end
285
292
 
@@ -303,7 +310,10 @@ module GoodJob
303
310
  AND pg_locks.objid = (('x' || substr(md5($2::text), 1, 16))::bit(64) << 32)::bit(32)::int
304
311
  AND pg_locks.pid = pg_backend_pid()
305
312
  SQL
306
- binds = [[nil, key], [nil, key]]
313
+ binds = [
314
+ ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
315
+ ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
316
+ ]
307
317
  self.class.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Owns Advisory Lock?', binds).any?
308
318
  end
309
319
 
@@ -120,7 +120,7 @@ module GoodJob # :nodoc:
120
120
  return if thread_error.is_a? AdapterCannotListenError
121
121
 
122
122
  if thread_error
123
- GoodJob.on_thread_error.call(thread_error) if GoodJob.on_thread_error.respond_to?(:call)
123
+ GoodJob._on_thread_error(thread_error)
124
124
  ActiveSupport::Notifications.instrument("notifier_notify_error.good_job", { error: thread_error })
125
125
 
126
126
  connection_error = CONNECTION_ERRORS.any? do |error_string|
@@ -91,7 +91,7 @@ module GoodJob # :nodoc:
91
91
  # @param thread_error [Exception, nil]
92
92
  # @return [void]
93
93
  def timer_observer(time, executed_task, thread_error)
94
- GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
94
+ GoodJob._on_thread_error(thread_error) if thread_error
95
95
  ActiveSupport::Notifications.instrument("finished_timer_task", { result: executed_task, error: thread_error, time: time })
96
96
  end
97
97
 
@@ -7,7 +7,7 @@ module GoodJob
7
7
  def self.task_observer(time, output, thread_error) # rubocop:disable Lint/UnusedMethodArgument
8
8
  return if thread_error.is_a? Concurrent::CancelledOperationError
9
9
 
10
- GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
10
+ GoodJob._on_thread_error(thread_error) if thread_error
11
11
  end
12
12
 
13
13
  def initialize(port:)
@@ -7,7 +7,7 @@ module GoodJob
7
7
 
8
8
  initializer "good_job.logger" do |_app|
9
9
  ActiveSupport.on_load(:good_job) do
10
- self.logger = ::Rails.logger
10
+ self.logger = ::Rails.logger if GoodJob.logger == GoodJob::DEFAULT_LOGGER
11
11
  end
12
12
  GoodJob::LogSubscriber.attach_to :good_job
13
13
  end
@@ -22,9 +22,19 @@ module GoodJob
22
22
  end
23
23
  end
24
24
 
25
- config.after_initialize do
26
- GoodJob::Scheduler.instances.each(&:warm_cache)
27
- GoodJob::CronManager.instances.each(&:start)
25
+ initializer 'good_job.rails_config' do
26
+ config.after_initialize do
27
+ GoodJob.logger = Rails.application.config.good_job.logger unless Rails.application.config.good_job.logger.nil?
28
+ GoodJob.on_thread_error = Rails.application.config.good_job.on_thread_error unless Rails.application.config.good_job.on_thread_error.nil?
29
+ GoodJob.preserve_job_records = Rails.application.config.good_job.preserve_job_records unless Rails.application.config.good_job.preserve_job_records.nil?
30
+ GoodJob.retry_on_unhandled_error = Rails.application.config.good_job.retry_on_unhandled_error unless Rails.application.config.good_job.retry_on_unhandled_error.nil?
31
+ end
32
+ end
33
+
34
+ initializer "good_job.start_async" do
35
+ config.after_initialize do
36
+ GoodJob::Adapter.instances.each(&:start_async)
37
+ end
28
38
  end
29
39
  end
30
40
  end
@@ -169,7 +169,7 @@ module GoodJob # :nodoc:
169
169
  # @return [void]
170
170
  def task_observer(time, output, thread_error)
171
171
  error = thread_error || (output.is_a?(GoodJob::ExecutionResult) ? output.unhandled_error : nil)
172
- GoodJob.on_thread_error.call(error) if error && GoodJob.on_thread_error.respond_to?(:call)
172
+ GoodJob._on_thread_error(error) if error
173
173
 
174
174
  instrument("finished_job_task", { result: output, error: thread_error, time: time })
175
175
  create_task if output
@@ -206,7 +206,7 @@ module GoodJob # :nodoc:
206
206
  end
207
207
 
208
208
  observer = lambda do |_time, _output, thread_error|
209
- GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
209
+ GoodJob._on_thread_error(thread_error) if thread_error
210
210
  create_task # If cache-warming exhausts the threads, ensure there isn't an executable task remaining
211
211
  end
212
212
  future.add_observer(observer, :call)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module GoodJob
3
3
  # GoodJob gem version.
4
- VERSION = '2.7.1'
4
+ VERSION = '2.7.2'
5
5
  end
data/lib/good_job.rb CHANGED
@@ -18,6 +18,8 @@ require "good_job/railtie"
18
18
  #
19
19
  # +GoodJob+ is the top-level namespace and exposes configuration attributes.
20
20
  module GoodJob
21
+ DEFAULT_LOGGER = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new($stdout))
22
+
21
23
  # @!attribute [rw] active_record_parent_class
22
24
  # @!scope class
23
25
  # The ActiveRecord parent class inherited by +GoodJob::Execution+ (default: +ActiveRecord::Base+).
@@ -34,7 +36,7 @@ module GoodJob
34
36
  # @return [Logger, nil]
35
37
  # @example Output GoodJob logs to a file:
36
38
  # GoodJob.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new("log/my_logs.log"))
37
- mattr_accessor :logger, default: ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new($stdout))
39
+ mattr_accessor :logger, default: DEFAULT_LOGGER
38
40
 
39
41
  # @!attribute [rw] preserve_job_records
40
42
  # @!scope class
@@ -66,6 +68,13 @@ module GoodJob
66
68
  # @return [Proc, nil]
67
69
  mattr_accessor :on_thread_error, default: nil
68
70
 
71
+ # Called with exception when a GoodJob thread raises an exception
72
+ # @param exception [Exception] Exception that was raised
73
+ # @return [void]
74
+ def self._on_thread_error(exception)
75
+ on_thread_error.call(exception) if on_thread_error.respond_to?(:call)
76
+ end
77
+
69
78
  # Stop executing jobs.
70
79
  # GoodJob does its work in pools of background threads.
71
80
  # When forking processes you should shut down these background threads before forking, and restart them after forking.
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: 2.7.1
4
+ version: 2.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-26 00:00:00.000000000 Z
11
+ date: 2021-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob