good_job 3.99.1 → 4.0.0

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +0 -61
  3. data/app/charts/good_job/scheduled_by_queue_chart.rb +2 -2
  4. data/app/controllers/good_job/cron_entries_controller.rb +0 -8
  5. data/app/controllers/good_job/metrics_controller.rb +1 -1
  6. data/app/controllers/good_job/performances_controller.rb +5 -9
  7. data/app/models/concerns/good_job/filterable.rb +1 -1
  8. data/app/models/good_job/base_execution.rb +104 -201
  9. data/app/models/good_job/cron_entry.rb +0 -2
  10. data/app/models/good_job/discrete_execution.rb +1 -31
  11. data/app/models/good_job/execution.rb +3 -7
  12. data/app/models/good_job/job.rb +37 -116
  13. data/app/models/good_job/process.rb +7 -20
  14. data/app/views/good_job/batches/index.html.erb +11 -15
  15. data/app/views/good_job/jobs/_executions.erb +1 -1
  16. data/app/views/good_job/jobs/_table.erb +1 -1
  17. data/app/views/good_job/jobs/show.html.erb +1 -8
  18. data/app/views/good_job/performances/show.html.erb +33 -40
  19. data/config/locales/de.yml +1 -4
  20. data/config/locales/en.yml +1 -4
  21. data/config/locales/es.yml +1 -4
  22. data/config/locales/fr.yml +1 -4
  23. data/config/locales/it.yml +1 -4
  24. data/config/locales/ja.yml +1 -4
  25. data/config/locales/ko.yml +1 -4
  26. data/config/locales/nl.yml +1 -4
  27. data/config/locales/pt-BR.yml +1 -4
  28. data/config/locales/ru.yml +1 -4
  29. data/config/locales/tr.yml +1 -4
  30. data/config/locales/uk.yml +1 -4
  31. data/lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb.erb +65 -3
  32. data/lib/good_job/active_job_extensions/batches.rb +1 -1
  33. data/lib/good_job/active_job_extensions/concurrency.rb +10 -10
  34. data/lib/good_job/adapter.rb +13 -24
  35. data/lib/good_job/current_thread.rb +6 -6
  36. data/lib/good_job/job_performer.rb +2 -2
  37. data/lib/good_job/log_subscriber.rb +2 -10
  38. data/lib/good_job/notifier.rb +3 -3
  39. data/lib/good_job/version.rb +1 -1
  40. data/lib/good_job.rb +17 -22
  41. metadata +16 -30
  42. data/lib/generators/good_job/templates/update/migrations/02_create_good_job_settings.rb.erb +0 -20
  43. data/lib/generators/good_job/templates/update/migrations/03_create_index_good_jobs_jobs_on_priority_created_at_when_unfinished.rb.erb +0 -19
  44. data/lib/generators/good_job/templates/update/migrations/04_create_good_job_batches.rb.erb +0 -35
  45. data/lib/generators/good_job/templates/update/migrations/05_create_good_job_executions.rb.erb +0 -33
  46. data/lib/generators/good_job/templates/update/migrations/06_create_good_jobs_error_event.rb.erb +0 -16
  47. data/lib/generators/good_job/templates/update/migrations/07_recreate_good_job_cron_indexes_with_conditional.rb.erb +0 -45
  48. data/lib/generators/good_job/templates/update/migrations/08_create_good_job_labels.rb.erb +0 -15
  49. data/lib/generators/good_job/templates/update/migrations/09_create_good_job_labels_index.rb.erb +0 -22
  50. data/lib/generators/good_job/templates/update/migrations/10_remove_good_job_active_id_index.rb.erb +0 -21
  51. data/lib/generators/good_job/templates/update/migrations/11_create_index_good_job_jobs_for_candidate_lookup.rb.erb +0 -19
  52. data/lib/generators/good_job/templates/update/migrations/12_create_good_job_execution_error_backtrace.rb.erb +0 -15
  53. data/lib/generators/good_job/templates/update/migrations/13_create_good_job_process_lock_ids.rb.erb +0 -18
  54. data/lib/generators/good_job/templates/update/migrations/14_create_good_job_process_lock_indexes.rb.erb +0 -38
  55. data/lib/generators/good_job/templates/update/migrations/15_create_good_job_execution_duration.rb.erb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7dd2e7c483f6ded0e42c21101bd4e7e0ff7e3ac75cdc47855f215b1484ead2bd
4
- data.tar.gz: c74390ec62b82ba8b2281b6b14ea241726e75ad9bc1669ddf06f35511acda998
3
+ metadata.gz: 3a4006c920a731f763e36a964e7eb161a292e8a4b34bffa4b60b95b75145c28c
4
+ data.tar.gz: f54b107db6ac1e2304a4ee9e2d34fa65032dc2b1ab0425e0be5ea42d39e5590b
5
5
  SHA512:
6
- metadata.gz: 7de33180257e794e418416b7f83ab00fa64121e64a69a6be46e7c86301cbf750b4ae5ee7851aad02501d48ca64baf38d94782ab89852ae4a79e55870c76df5e3
7
- data.tar.gz: 36bc0111ecba9df0e983e44c2c418325b745fcc90fa8295d71da44ff4d63ad6fed733760e6355aa3f18a663d3d0d4d9df75cfac23f97cc2a2964b29fe4d5d99c
6
+ metadata.gz: 4474aaa0540dc5ff1bba65e8807a6fa69a9901f2e68051c57cf954e30270e9e6d7eaf52a3ce8ec7de6f48b16fc60fa05e796f595f14dfda41a76cbeb5b042543
7
+ data.tar.gz: cf8103c84fceffe91e4f7b0f5083c3989d2312a17ce96b1db01d7726a99b651c7d850f83fe23075c5a01628a825ef71d335d0eb42e91a478a62dd7772ee95e54
data/CHANGELOG.md CHANGED
@@ -1,66 +1,5 @@
1
1
  # Changelog
2
2
 
3
- ## [v3.99.1](https://github.com/bensheldon/good_job/tree/v3.99.1) (2024-07-10)
4
-
5
- [Full Changelog](https://github.com/bensheldon/good_job/compare/v4.0.3...v3.99.1)
6
-
7
- **Merged pull requests:**
8
-
9
- - Add a little more wording to the v4 "ready to upgrade" instructions [\#1415](https://github.com/bensheldon/good_job/pull/1415) ([bensheldon](https://github.com/bensheldon))
10
-
11
- ## [v4.0.3](https://github.com/bensheldon/good_job/tree/v4.0.3) (2024-07-10)
12
-
13
- [Full Changelog](https://github.com/bensheldon/good_job/compare/v4.0.2...v4.0.3)
14
-
15
- **Fixed bugs:**
16
-
17
- - Only set duration attribute to interval on Rails 6.1 [\#1412](https://github.com/bensheldon/good_job/pull/1412) ([bdewater-thatch](https://github.com/bdewater-thatch))
18
-
19
- **Closed issues:**
20
-
21
- - GoodJob error: TypeError: can't cast ActiveSupport::Duration \(on v4.0.0\) [\#1413](https://github.com/bensheldon/good_job/issues/1413)
22
- - Question: is it possible to clean a set of scheduled jobs \(by class name\) from console? [\#1410](https://github.com/bensheldon/good_job/issues/1410)
23
- - "Couldn't find GoodJob::BatchRecord" error [\#1387](https://github.com/bensheldon/good_job/issues/1387)
24
- - Empty alerts "\[\]"? [\#1372](https://github.com/bensheldon/good_job/issues/1372)
25
- - Release GoodJob 4.0 [\#764](https://github.com/bensheldon/good_job/issues/764)
26
-
27
- **Merged pull requests:**
28
-
29
- - Add Active Support load hooks for Job and \(Discrete\)Execution; move all outside class definition bodies [\#1414](https://github.com/bensheldon/good_job/pull/1414) ([bensheldon](https://github.com/bensheldon))
30
-
31
- ## [v4.0.2](https://github.com/bensheldon/good_job/tree/v4.0.2) (2024-07-08)
32
-
33
- [Full Changelog](https://github.com/bensheldon/good_job/compare/v4.0.1...v4.0.2)
34
-
35
- **Fixed bugs:**
36
-
37
- - Fix a rails 6.1 deprecation warning for the duration attribute [\#1408](https://github.com/bensheldon/good_job/pull/1408) ([Earlopain](https://github.com/Earlopain))
38
- - Actually remove deprecated configuration for `cleanup_interval_seconds`, `cleanup_interval_jobs`; remove deprecated `Lockable` [\#1406](https://github.com/bensheldon/good_job/pull/1406) ([bensheldon](https://github.com/bensheldon))
39
-
40
- **Closed issues:**
41
-
42
- - PG::UndefinedColumn: ERROR: column good\_job\_processes.lock\_type does not exist [\#1405](https://github.com/bensheldon/good_job/issues/1405)
43
- - undefined method `duration=' for an instance of GoodJob::Execution [\#1404](https://github.com/bensheldon/good_job/issues/1404)
44
- - v3 deprecations are still present [\#1399](https://github.com/bensheldon/good_job/issues/1399)
45
-
46
- **Merged pull requests:**
47
-
48
- - Fix Batch integration test to not exhaust database connection thread pool [\#1409](https://github.com/bensheldon/good_job/pull/1409) ([bensheldon](https://github.com/bensheldon))
49
- - Discrete cleanup [\#1401](https://github.com/bensheldon/good_job/pull/1401) ([Earlopain](https://github.com/Earlopain))
50
-
51
- ## [v4.0.1](https://github.com/bensheldon/good_job/tree/v4.0.1) (2024-07-08)
52
-
53
- [Full Changelog](https://github.com/bensheldon/good_job/compare/v4.0.0...v4.0.1)
54
-
55
- **Fixed bugs:**
56
-
57
- - Actually change `smaller_number_is_higher_priority` for v4 [\#1402](https://github.com/bensheldon/good_job/pull/1402) ([Earlopain](https://github.com/Earlopain))
58
-
59
- **Merged pull requests:**
60
-
61
- - Bump prism/rbi dev dependency [\#1403](https://github.com/bensheldon/good_job/pull/1403) ([Earlopain](https://github.com/Earlopain))
62
- - Use index action for the performance controller [\#1398](https://github.com/bensheldon/good_job/pull/1398) ([Earlopain](https://github.com/Earlopain))
63
-
64
3
  ## [v4.0.0](https://github.com/bensheldon/good_job/tree/v4.0.0) (2024-07-07)
65
4
 
66
5
  [Full Changelog](https://github.com/bensheldon/good_job/compare/v3.99.0...v4.0.0)
@@ -11,7 +11,7 @@ module GoodJob
11
11
  start_time = end_time - 1.day
12
12
  table_name = GoodJob::Job.table_name
13
13
 
14
- count_query = Arel.sql(GoodJob::Execution.pg_or_jdbc_query(<<~SQL.squish))
14
+ count_query = Arel.sql(GoodJob::Job.pg_or_jdbc_query(<<~SQL.squish))
15
15
  SELECT *
16
16
  FROM generate_series(
17
17
  date_trunc('hour', $1::timestamp),
@@ -35,7 +35,7 @@ module GoodJob
35
35
  ActiveRecord::Relation::QueryAttribute.new('start_time', start_time, ActiveRecord::Type::DateTime.new),
36
36
  ActiveRecord::Relation::QueryAttribute.new('end_time', end_time, ActiveRecord::Type::DateTime.new),
37
37
  ]
38
- executions_data = GoodJob::Execution.connection.exec_query(GoodJob::Execution.pg_or_jdbc_query(count_query), "GoodJob Dashboard Chart", binds)
38
+ executions_data = GoodJob::Job.connection.exec_query(GoodJob::Job.pg_or_jdbc_query(count_query), "GoodJob Dashboard Chart", binds)
39
39
 
40
40
  queue_names = executions_data.reject { |d| d['count'].nil? }.map { |d| d['queue_name'] || BaseFilter::EMPTY }.uniq
41
41
  labels = []
@@ -2,8 +2,6 @@
2
2
 
3
3
  module GoodJob
4
4
  class CronEntriesController < GoodJob::ApplicationController
5
- before_action :check_settings_migration!, only: [:enable, :disable]
6
-
7
5
  def index
8
6
  @cron_entries = CronEntry.all
9
7
  end
@@ -30,11 +28,5 @@ module GoodJob
30
28
  @cron_entry.disable
31
29
  redirect_back(fallback_location: cron_entries_path, notice: t(".notice"))
32
30
  end
33
-
34
- private
35
-
36
- def check_settings_migration!
37
- redirect_back(fallback_location: cron_entries_path, alert: t("good_job.cron_entries.pending_migrations")) unless GoodJob::Setting.migrated?
38
- end
39
31
  end
40
32
  end
@@ -4,7 +4,7 @@ module GoodJob
4
4
  class MetricsController < ApplicationController
5
5
  def primary_nav
6
6
  jobs_count = GoodJob::Job.count
7
- batches_count = GoodJob::BatchRecord.migrated? ? GoodJob::BatchRecord.all.size : 0
7
+ batches_count = GoodJob::BatchRecord.all.size
8
8
  cron_entries_count = GoodJob::CronEntry.all.size
9
9
  processes_count = GoodJob::Process.active.count
10
10
 
@@ -3,21 +3,17 @@
3
3
  module GoodJob
4
4
  class PerformancesController < ApplicationController
5
5
  def show
6
- if GoodJob::DiscreteExecution.duration_interval_migrated?
7
- @performances = GoodJob::DiscreteExecution
8
- .where.not(job_class: nil)
9
- .group(:job_class)
10
- .select("
6
+ @performances = GoodJob::DiscreteExecution
7
+ .where.not(job_class: nil)
8
+ .group(:job_class)
9
+ .select("
11
10
  job_class,
12
11
  COUNT(*) AS executions_count,
13
12
  AVG(duration) AS avg_duration,
14
13
  MIN(duration) AS min_duration,
15
14
  MAX(duration) AS max_duration
16
15
  ")
17
- .order("job_class")
18
- else
19
- @needs_upgrade = true
20
- end
16
+ .order("job_class")
21
17
  end
22
18
  end
23
19
  end
@@ -35,7 +35,7 @@ module GoodJob
35
35
  next if query.blank?
36
36
 
37
37
  # TODO: turn this into proper bind parameters in Arel
38
- tsvector = "(to_tsvector('english', id::text) || to_tsvector('english', COALESCE(active_job_id::text, '')) || to_tsvector('english', serialized_params) || to_tsvector('english', COALESCE(error, ''))#{" || to_tsvector('english', COALESCE(array_to_string(labels, ' '), ''))" if labels_migrated?})"
38
+ tsvector = "(to_tsvector('english', id::text) || to_tsvector('english', COALESCE(active_job_id::text, '')) || to_tsvector('english', serialized_params) || to_tsvector('english', COALESCE(error, '')) || to_tsvector('english', COALESCE(array_to_string(labels, ' '), '')))"
39
39
  to_tsquery_function = database_supports_websearch_to_tsquery? ? 'websearch_to_tsquery' : 'plainto_tsquery'
40
40
  where("#{tsvector} @@ #{to_tsquery_function}(?)", query)
41
41
  .order(sanitize_sql_for_order([Arel.sql("ts_rank(#{tsvector}, #{to_tsquery_function}(?))"), query]) => 'DESC')
@@ -74,9 +74,6 @@ module GoodJob
74
74
  end
75
75
  end
76
76
 
77
- belongs_to :batch, class_name: 'GoodJob::BatchRecord', optional: true, inverse_of: :executions
78
- has_many :discrete_executions, class_name: 'GoodJob::DiscreteExecution', foreign_key: 'active_job_id', primary_key: 'active_job_id', inverse_of: :execution # rubocop:disable Rails/HasManyOrHasOneDependent
79
-
80
77
  # With a given class name
81
78
  # @!method job_class(name)
82
79
  # @!scope class
@@ -84,11 +81,6 @@ module GoodJob
84
81
  # @return [ActiveRecord::Relation]
85
82
  scope :job_class, ->(name) { where(params_job_class.eq(name)) }
86
83
 
87
- after_destroy lambda {
88
- GoodJob::DiscreteExecution.where(active_job_id: active_job_id).delete_all if discrete? # TODO: move into association `dependent: :delete_all` after v4
89
- self.class.active_job_id(active_job_id).delete_all
90
- }, if: -> { @_destroy_job }
91
-
92
84
  # Get jobs with given ActiveJob ID
93
85
  # @!method active_job_id(active_job_id)
94
86
  # @!scope class
@@ -226,67 +218,12 @@ module GoodJob
226
218
  end
227
219
 
228
220
  def discrete_support?
229
- GoodJob::DiscreteExecution.migrated?
230
- end
231
-
232
- def error_event_migrated?
233
- return true if columns_hash["error_event"].present?
234
-
235
- migration_pending_warning!
236
- false
237
- end
238
-
239
- def cron_indices_migrated?
240
- return true if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at_cond)
241
-
242
- migration_pending_warning!
243
- false
244
- end
245
-
246
- def labels_migrated?
247
- return true if columns_hash["labels"].present?
248
-
249
- migration_pending_warning!
250
- false
251
- end
252
-
253
- def labels_indices_migrated?
254
- return true if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_labels)
255
-
256
- migration_pending_warning!
257
- false
221
+ true
258
222
  end
259
-
260
- def active_job_id_index_removal_migrated?
261
- return true unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id)
262
-
263
- migration_pending_warning!
264
- false
265
- end
266
-
267
- def candidate_lookup_index_migrated?
268
- return true if connection.index_name_exists?(:good_jobs, :index_good_job_jobs_for_candidate_lookup)
269
-
270
- migration_pending_warning!
271
- false
272
- end
273
-
274
- def process_lock_migrated?
275
- return true if connection.index_name_exists?(:good_job_executions, :index_good_job_executions_on_process_id_and_created_at)
276
-
277
- migration_pending_warning!
278
- false
279
- end
280
- end
281
-
282
- # The ActiveJob job class, as a string
283
- # @return [String]
284
- def job_class
285
- discrete? ? attributes['job_class'] : serialized_params['job_class']
286
223
  end
287
224
 
288
225
  def discrete?
289
- self.class.discrete_support? && is_discrete?
226
+ is_discrete?
290
227
  end
291
228
 
292
229
  # Build an ActiveJob instance and deserialize the arguments, using `#active_job_data`.
@@ -304,54 +241,54 @@ module GoodJob
304
241
  raise unless ignore_deserialization_errors
305
242
  end
306
243
 
307
- def self.build_for_enqueue(active_job, overrides = {})
308
- new(**enqueue_args(active_job, overrides))
244
+ def self.build_for_enqueue(active_job, scheduled_at: nil)
245
+ new(**enqueue_args(active_job, scheduled_at: scheduled_at))
309
246
  end
310
247
 
311
248
  # Construct arguments for GoodJob::Execution from an ActiveJob instance.
312
- def self.enqueue_args(active_job, overrides = {})
313
- if active_job.priority && GoodJob.configuration.smaller_number_is_higher_priority.in?([nil, false])
314
- GoodJob.deprecator.warn(<<~DEPRECATION)
315
- The next major version of GoodJob (v4.0) will change job `priority` to give smaller numbers higher priority (default: `0`), in accordance with Active Job's definition of priority.
316
- To opt-in to this behavior now, set `config.good_job.smaller_number_is_higher_priority = true` in your GoodJob initializer or application.rb.
317
- DEPRECATION
318
- end
319
-
249
+ def self.enqueue_args(active_job, scheduled_at: nil)
320
250
  execution_args = {
251
+ id: active_job.job_id,
321
252
  active_job_id: active_job.job_id,
253
+ job_class: active_job.class.name,
322
254
  queue_name: active_job.queue_name.presence || DEFAULT_QUEUE_NAME,
323
255
  priority: active_job.priority || DEFAULT_PRIORITY,
324
256
  serialized_params: active_job.serialize,
257
+ created_at: Time.current,
325
258
  }
326
- execution_args[:scheduled_at] = Time.zone.at(active_job.scheduled_at) if active_job.scheduled_at
259
+
260
+ execution_args[:scheduled_at] = if scheduled_at
261
+ scheduled_at
262
+ elsif active_job.scheduled_at
263
+ Time.zone.at(active_job.scheduled_at)
264
+ else
265
+ execution_args[:created_at]
266
+ end
267
+
327
268
  execution_args[:concurrency_key] = active_job.good_job_concurrency_key if active_job.respond_to?(:good_job_concurrency_key)
328
269
 
329
- if active_job.respond_to?(:good_job_labels) && active_job.good_job_labels.any? && labels_migrated?
270
+ if active_job.respond_to?(:good_job_labels) && active_job.good_job_labels.any?
330
271
  labels = active_job.good_job_labels.dup
331
272
  labels.map! { |label| label.to_s.strip.presence }
332
273
  labels.tap(&:compact!).tap(&:uniq!)
333
274
  execution_args[:labels] = labels
334
275
  end
335
276
 
336
- reenqueued_current_execution = CurrentThread.active_job_id && CurrentThread.active_job_id == active_job.job_id
337
- current_execution = CurrentThread.execution
277
+ reenqueued_current_job = CurrentThread.active_job_id && CurrentThread.active_job_id == active_job.job_id
278
+ current_job = CurrentThread.job
338
279
 
339
- if reenqueued_current_execution
340
- if GoodJob::BatchRecord.migrated?
341
- execution_args[:batch_id] = current_execution.batch_id
342
- execution_args[:batch_callback_id] = current_execution.batch_callback_id
343
- end
344
- execution_args[:cron_key] = current_execution.cron_key
280
+ if reenqueued_current_job
281
+ execution_args[:batch_id] = current_job.batch_id
282
+ execution_args[:batch_callback_id] = current_job.batch_callback_id
283
+ execution_args[:cron_key] = current_job.cron_key
345
284
  else
346
- if GoodJob::BatchRecord.migrated?
347
- execution_args[:batch_id] = GoodJob::Batch.current_batch_id
348
- execution_args[:batch_callback_id] = GoodJob::Batch.current_batch_callback_id
349
- end
285
+ execution_args[:batch_id] = GoodJob::Batch.current_batch_id
286
+ execution_args[:batch_callback_id] = GoodJob::Batch.current_batch_callback_id
350
287
  execution_args[:cron_key] = CurrentThread.cron_key
351
288
  execution_args[:cron_at] = CurrentThread.cron_at
352
289
  end
353
290
 
354
- execution_args.merge(overrides)
291
+ execution_args
355
292
  end
356
293
 
357
294
  # Finds the next eligible Execution, acquire an advisory lock related to it, and
@@ -363,21 +300,23 @@ module GoodJob
363
300
  # raised, if any (if the job raised, then the second array entry will be
364
301
  # +nil+). If there were no jobs to execute, returns +nil+.
365
302
  def self.perform_with_advisory_lock(lock_id:, parsed_queues: nil, queue_select_limit: nil)
366
- execution = nil
303
+ job = nil
367
304
  result = nil
368
305
 
369
- unfinished.dequeueing_ordered(parsed_queues).only_scheduled.limit(1).with_advisory_lock(select_limit: queue_select_limit) do |executions|
370
- execution = executions.first
371
- if execution&.executable?
372
- yield(execution) if block_given?
373
- result = execution.perform(lock_id: lock_id)
306
+ unfinished.dequeueing_ordered(parsed_queues).only_scheduled.limit(1).with_advisory_lock(select_limit: queue_select_limit) do |jobs|
307
+ job = jobs.first
308
+
309
+ if job&.executable?
310
+ yield(job) if block_given?
311
+
312
+ result = job.perform(lock_id: lock_id)
374
313
  else
375
- execution = nil
314
+ job = nil
376
315
  yield(nil) if block_given?
377
316
  end
378
317
  end
379
318
 
380
- execution&.run_callbacks(:perform_unlocked)
319
+ job&.run_callbacks(:perform_unlocked)
381
320
  result
382
321
  end
383
322
 
@@ -413,46 +352,38 @@ module GoodJob
413
352
  # The new {Execution} instance representing the queued ActiveJob job.
414
353
  def self.enqueue(active_job, scheduled_at: nil, create_with_advisory_lock: false)
415
354
  ActiveSupport::Notifications.instrument("enqueue_job.good_job", { active_job: active_job, scheduled_at: scheduled_at, create_with_advisory_lock: create_with_advisory_lock }) do |instrument_payload|
416
- current_execution = CurrentThread.execution
355
+ current_job = CurrentThread.job
417
356
 
418
- retried = current_execution && current_execution.active_job_id == active_job.job_id
357
+ retried = current_job && current_job.active_job_id == active_job.job_id
419
358
  if retried
420
- if current_execution.discrete?
421
- execution = current_execution
422
- execution.assign_attributes(enqueue_args(active_job, { scheduled_at: scheduled_at }))
423
- execution.scheduled_at ||= Time.current
424
- # TODO: these values ideally shouldn't be persisted until the current_execution is finished
425
- # which will require handling `retry_job` being called from outside the execution context.
426
- execution.performed_at = nil
427
- execution.finished_at = nil
428
- else
429
- execution = build_for_enqueue(active_job, { scheduled_at: scheduled_at })
430
- end
359
+ job = current_job
360
+ job.assign_attributes(enqueue_args(active_job, scheduled_at: scheduled_at))
361
+ job.scheduled_at ||= Time.current
362
+ # TODO: these values ideally shouldn't be persisted until the current_job is finished
363
+ # which will require handling `retry_job` being called from outside the job context.
364
+ job.performed_at = nil
365
+ job.finished_at = nil
431
366
  else
432
- execution = build_for_enqueue(active_job, { scheduled_at: scheduled_at })
433
- execution.make_discrete if discrete_support?
367
+ job = build_for_enqueue(active_job, scheduled_at: scheduled_at)
434
368
  end
435
369
 
436
370
  if create_with_advisory_lock
437
- if execution.persisted?
438
- execution.advisory_lock
371
+ if job.persisted?
372
+ job.advisory_lock
439
373
  else
440
- execution.create_with_advisory_lock = true
374
+ job.create_with_advisory_lock = true
441
375
  end
442
376
  end
443
377
 
444
- instrument_payload[:execution] = execution
445
- execution.save!
378
+ instrument_payload[:job] = job
379
+ job.save!
446
380
 
447
- if retried
448
- CurrentThread.execution_retried = execution
449
- CurrentThread.execution.retried_good_job_id = execution.id unless current_execution.discrete?
450
- else
451
- CurrentThread.execution_retried = nil
452
- end
381
+ CurrentThread.execution_retried = (job if retried)
453
382
 
454
- active_job.provider_job_id = execution.id
455
- execution
383
+ active_job.provider_job_id = job.id
384
+ raise "These should be equal" if active_job.provider_job_id != active_job.job_id
385
+
386
+ job
456
387
  end
457
388
  end
458
389
 
@@ -476,64 +407,47 @@ module GoodJob
476
407
  discrete_execution = nil
477
408
  result = GoodJob::CurrentThread.within do |current_thread|
478
409
  current_thread.reset
479
- current_thread.execution = self
410
+ current_thread.job = self
480
411
 
481
412
  existing_performed_at = performed_at
482
413
  if existing_performed_at
483
414
  current_thread.execution_interrupted = existing_performed_at
484
415
 
485
- if discrete?
486
- interrupt_error_string = self.class.format_error(GoodJob::InterruptError.new("Interrupted after starting perform at '#{existing_performed_at}'"))
487
- self.error = interrupt_error_string
488
- self.error_event = ERROR_EVENT_INTERRUPTED if self.class.error_event_migrated?
489
- monotonic_duration = (::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - monotonic_start).seconds
490
-
491
- discrete_execution_attrs = {
492
- error: interrupt_error_string,
493
- finished_at: job_performed_at,
494
- }
495
- discrete_execution_attrs[:error_event] = GoodJob::ErrorEvents::ERROR_EVENT_ENUMS[GoodJob::ErrorEvents::ERROR_EVENT_INTERRUPTED] if self.class.error_event_migrated?
496
- discrete_execution_attrs[:duration] = monotonic_duration if GoodJob::DiscreteExecution.duration_interval_usable?
497
- discrete_executions.where(finished_at: nil).where.not(performed_at: nil).update_all(discrete_execution_attrs) # rubocop:disable Rails/SkipsModelValidations
498
- end
416
+ interrupt_error_string = self.class.format_error(GoodJob::InterruptError.new("Interrupted after starting perform at '#{existing_performed_at}'"))
417
+ self.error = interrupt_error_string
418
+ self.error_event = ERROR_EVENT_INTERRUPTED
419
+ monotonic_duration = (::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - monotonic_start).seconds
420
+
421
+ discrete_execution_attrs = {
422
+ error: interrupt_error_string,
423
+ finished_at: job_performed_at,
424
+ }
425
+ discrete_execution_attrs[:error_event] = GoodJob::ErrorEvents::ERROR_EVENT_ENUMS[GoodJob::ErrorEvents::ERROR_EVENT_INTERRUPTED]
426
+ discrete_execution_attrs[:duration] = monotonic_duration
427
+ discrete_executions.where(finished_at: nil).where.not(performed_at: nil).update_all(discrete_execution_attrs) # rubocop:disable Rails/SkipsModelValidations
499
428
  end
500
429
 
501
- if discrete?
502
- transaction do
503
- discrete_execution_attrs = {
504
- job_class: job_class,
505
- queue_name: queue_name,
506
- serialized_params: serialized_params,
507
- scheduled_at: (scheduled_at || created_at),
508
- created_at: job_performed_at,
509
- }
510
- discrete_execution_attrs[:process_id] = lock_id if GoodJob::DiscreteExecution.columns_hash.key?("process_id")
511
-
512
- execution_attrs = {
513
- performed_at: job_performed_at,
514
- executions_count: ((executions_count || 0) + 1),
515
- }
516
- if GoodJob::Execution.columns_hash.key?("locked_by_id")
517
- execution_attrs[:locked_by_id] = lock_id
518
- execution_attrs[:locked_at] = Time.current
519
- end
520
-
521
- discrete_execution = discrete_executions.create!(discrete_execution_attrs)
522
- update!(execution_attrs)
523
- end
524
- else
525
- execution_attrs = {
430
+ transaction do
431
+ discrete_execution_attrs = {
432
+ job_class: job_class,
433
+ queue_name: queue_name,
434
+ serialized_params: serialized_params,
435
+ scheduled_at: (scheduled_at || created_at),
436
+ created_at: job_performed_at,
437
+ process_id: lock_id,
438
+ }
439
+ job_attrs = {
526
440
  performed_at: job_performed_at,
441
+ executions_count: ((executions_count || 0) + 1),
442
+ locked_by_id: lock_id,
443
+ locked_at: Time.current,
527
444
  }
528
- if GoodJob::Execution.columns_hash.key?("locked_by_id")
529
- execution_attrs[:locked_by_id] = lock_id
530
- execution_attrs[:locked_at] = Time.current
531
- end
532
445
 
533
- update!(execution_attrs)
446
+ discrete_execution = discrete_executions.create!(discrete_execution_attrs)
447
+ update!(job_attrs)
534
448
  end
535
449
 
536
- ActiveSupport::Notifications.instrument("perform_job.good_job", { execution: self, process_id: current_thread.process_id, thread_name: current_thread.thread_name }) do |instrument_payload|
450
+ ActiveSupport::Notifications.instrument("perform_job.good_job", { job: self, execution: discrete_execution, process_id: current_thread.process_id, thread_name: current_thread.thread_name }) do |instrument_payload|
537
451
  value = ActiveJob::Base.execute(active_job_data)
538
452
 
539
453
  if value.is_a?(Exception)
@@ -584,50 +498,39 @@ module GoodJob
584
498
  error_string = self.class.format_error(job_error)
585
499
 
586
500
  job_attributes[:error] = error_string
587
- job_attributes[:error_event] = result.error_event if self.class.error_event_migrated?
588
- if discrete_execution
589
- discrete_execution.error = error_string
590
- discrete_execution.error_event = result.error_event
591
- discrete_execution.error_backtrace = job_error.backtrace if discrete_execution.class.backtrace_migrated?
592
- end
501
+ job_attributes[:error_event] = result.error_event
502
+
503
+ discrete_execution.error = error_string
504
+ discrete_execution.error_event = result.error_event
505
+ discrete_execution.error_backtrace = job_error.backtrace
593
506
  else
594
507
  job_attributes[:error] = nil
595
508
  job_attributes[:error_event] = nil
596
509
  end
597
- job_attributes.delete(:error_event) unless self.class.error_event_migrated?
598
510
 
599
511
  job_finished_at = Time.current
600
512
  monotonic_duration = (::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - monotonic_start).seconds
601
513
  job_attributes[:finished_at] = job_finished_at
602
- if discrete_execution
603
- discrete_execution.finished_at = job_finished_at
604
- discrete_execution.duration = monotonic_duration if GoodJob::DiscreteExecution.duration_interval_usable?
605
- end
514
+
515
+ discrete_execution.finished_at = job_finished_at
516
+ discrete_execution.duration = monotonic_duration
606
517
 
607
518
  retry_unhandled_error = result.unhandled_error && GoodJob.retry_on_unhandled_error
608
519
  reenqueued = result.retried? || retried_good_job_id.present? || retry_unhandled_error
609
520
  if reenqueued
610
- if discrete_execution
611
- job_attributes[:performed_at] = nil
612
- job_attributes[:finished_at] = nil
613
- else
614
- job_attributes[:retried_good_job_id] = retried_good_job_id
615
- job_attributes[:finished_at] = nil if retry_unhandled_error
616
- end
521
+ job_attributes[:performed_at] = nil
522
+ job_attributes[:finished_at] = nil
617
523
  end
618
524
 
525
+ assign_attributes(job_attributes)
619
526
  preserve_unhandled = (result.unhandled_error && (GoodJob.retry_on_unhandled_error || GoodJob.preserve_job_records == :on_unhandled_error))
620
- if GoodJob.preserve_job_records == true || reenqueued || preserve_unhandled || cron_key.present?
621
- if discrete_execution
622
- transaction do
623
- discrete_execution.save!
624
- update!(job_attributes)
625
- end
626
- else
627
- update!(job_attributes)
527
+ if finished_at.blank? || GoodJob.preserve_job_records == true || reenqueued || preserve_unhandled || cron_key.present?
528
+ transaction do
529
+ discrete_execution.save!
530
+ save!
628
531
  end
629
532
  else
630
- destroy_job
533
+ destroy!
631
534
  end
632
535
 
633
536
  result
@@ -708,7 +611,7 @@ module GoodJob
708
611
  end
709
612
 
710
613
  def continue_discard_or_finish_batch
711
- batch._continue_discard_or_finish(self) if GoodJob::BatchRecord.migrated? && batch.present?
614
+ batch._continue_discard_or_finish(self) if batch.present?
712
615
  end
713
616
 
714
617
  def active_job_data
@@ -716,7 +619,7 @@ module GoodJob
716
619
  .tap do |job_data|
717
620
  job_data["provider_job_id"] = id
718
621
  job_data["good_job_concurrency_key"] = concurrency_key if concurrency_key
719
- job_data["good_job_labels"] = Array(labels) if self.class.labels_migrated? && labels.present?
622
+ job_data["good_job_labels"] = Array(labels) if labels.present?
720
623
  end
721
624
  end
722
625
  end
@@ -72,8 +72,6 @@ module GoodJob # :nodoc:
72
72
  end
73
73
 
74
74
  def enabled?
75
- return true unless GoodJob::Setting.migrated?
76
-
77
75
  GoodJob::Setting.cron_key_enabled?(key, default: enabled_by_default?)
78
76
  end
79
77