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
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.99.1
4
+ version: 4.0.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: 2024-07-10 00:00:00.000000000 Z
11
+ date: 2024-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -16,84 +16,84 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.0
19
+ version: 6.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 6.0.0
26
+ version: 6.1.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 6.0.0
33
+ version: 6.1.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 6.0.0
40
+ version: 6.1.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: concurrent-ruby
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 1.0.2
47
+ version: 1.3.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 1.0.2
54
+ version: 1.3.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: fugit
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '1.1'
61
+ version: 1.11.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '1.1'
68
+ version: 1.11.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: railties
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: 6.0.0
75
+ version: 6.1.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: 6.0.0
82
+ version: 6.1.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: thor
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: 0.14.1
89
+ version: 1.0.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: 0.14.1
96
+ version: 1.0.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: capybara
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -351,20 +351,6 @@ files:
351
351
  - lib/generators/good_job/install_generator.rb
352
352
  - lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb
353
353
  - lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb.erb
354
- - lib/generators/good_job/templates/update/migrations/02_create_good_job_settings.rb.erb
355
- - lib/generators/good_job/templates/update/migrations/03_create_index_good_jobs_jobs_on_priority_created_at_when_unfinished.rb.erb
356
- - lib/generators/good_job/templates/update/migrations/04_create_good_job_batches.rb.erb
357
- - lib/generators/good_job/templates/update/migrations/05_create_good_job_executions.rb.erb
358
- - lib/generators/good_job/templates/update/migrations/06_create_good_jobs_error_event.rb.erb
359
- - lib/generators/good_job/templates/update/migrations/07_recreate_good_job_cron_indexes_with_conditional.rb.erb
360
- - lib/generators/good_job/templates/update/migrations/08_create_good_job_labels.rb.erb
361
- - lib/generators/good_job/templates/update/migrations/09_create_good_job_labels_index.rb.erb
362
- - lib/generators/good_job/templates/update/migrations/10_remove_good_job_active_id_index.rb.erb
363
- - lib/generators/good_job/templates/update/migrations/11_create_index_good_job_jobs_for_candidate_lookup.rb.erb
364
- - lib/generators/good_job/templates/update/migrations/12_create_good_job_execution_error_backtrace.rb.erb
365
- - lib/generators/good_job/templates/update/migrations/13_create_good_job_process_lock_ids.rb.erb
366
- - lib/generators/good_job/templates/update/migrations/14_create_good_job_process_lock_indexes.rb.erb
367
- - lib/generators/good_job/templates/update/migrations/15_create_good_job_execution_duration.rb.erb
368
354
  - lib/generators/good_job/update_generator.rb
369
355
  - lib/good_job.rb
370
356
  - lib/good_job/active_job_extensions/batches.rb
@@ -430,14 +416,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
430
416
  requirements:
431
417
  - - ">="
432
418
  - !ruby/object:Gem::Version
433
- version: 2.6.0
419
+ version: 3.0.0
434
420
  required_rubygems_version: !ruby/object:Gem::Requirement
435
421
  requirements:
436
422
  - - ">="
437
423
  - !ruby/object:Gem::Version
438
424
  version: '0'
439
425
  requirements: []
440
- rubygems_version: 3.5.9
426
+ rubygems_version: 3.5.14
441
427
  signing_key:
442
428
  specification_version: 4
443
429
  summary: A multithreaded, Postgres-based ActiveJob backend for Ruby on Rails
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobSettings < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- reversible do |dir|
6
- dir.up do
7
- # Ensure this incremental update migration is idempotent
8
- # with monolithic install migration.
9
- return if connection.table_exists?(:good_job_settings)
10
- end
11
- end
12
-
13
- create_table :good_job_settings, id: :uuid do |t|
14
- t.timestamps
15
- t.text :key
16
- t.jsonb :value
17
- t.index :key, unique: true
18
- end
19
- end
20
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateIndexGoodJobsJobsOnPriorityCreatedAtWhenUnfinished < ActiveRecord::Migration<%= migration_version %>
4
- disable_ddl_transaction!
5
-
6
- def change
7
- reversible do |dir|
8
- dir.up do
9
- # Ensure this incremental update migration is idempotent
10
- # with monolithic install migration.
11
- return if connection.index_name_exists?(:good_jobs, :index_good_jobs_jobs_on_priority_created_at_when_unfinished)
12
- end
13
- end
14
-
15
- add_index :good_jobs, [:priority, :created_at], order: { priority: "DESC NULLS LAST", created_at: :asc },
16
- where: "finished_at IS NULL", name: :index_good_jobs_jobs_on_priority_created_at_when_unfinished,
17
- algorithm: :concurrently
18
- end
19
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobBatches < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- reversible do |dir|
6
- dir.up do
7
- # Ensure this incremental update migration is idempotent
8
- # with monolithic install migration.
9
- return if connection.table_exists?(:good_job_batches)
10
- end
11
- end
12
-
13
- create_table :good_job_batches, id: :uuid do |t|
14
- t.timestamps
15
- t.text :description
16
- t.jsonb :serialized_properties
17
- t.text :on_finish
18
- t.text :on_success
19
- t.text :on_discard
20
- t.text :callback_queue_name
21
- t.integer :callback_priority
22
- t.datetime :enqueued_at
23
- t.datetime :discarded_at
24
- t.datetime :finished_at
25
- end
26
-
27
- change_table :good_jobs do |t|
28
- t.uuid :batch_id
29
- t.uuid :batch_callback_id
30
-
31
- t.index :batch_id, where: "batch_id IS NOT NULL"
32
- t.index :batch_callback_id, where: "batch_callback_id IS NOT NULL"
33
- end
34
- end
35
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobExecutions < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- reversible do |dir|
6
- dir.up do
7
- # Ensure this incremental update migration is idempotent
8
- # with monolithic install migration.
9
- return if connection.table_exists?(:good_job_executions)
10
- end
11
- end
12
-
13
- create_table :good_job_executions, id: :uuid do |t|
14
- t.timestamps
15
-
16
- t.uuid :active_job_id, null: false
17
- t.text :job_class
18
- t.text :queue_name
19
- t.jsonb :serialized_params
20
- t.datetime :scheduled_at
21
- t.datetime :finished_at
22
- t.text :error
23
-
24
- t.index [:active_job_id, :created_at], name: :index_good_job_executions_on_active_job_id_and_created_at
25
- end
26
-
27
- change_table :good_jobs do |t|
28
- t.boolean :is_discrete
29
- t.integer :executions_count
30
- t.text :job_class
31
- end
32
- end
33
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobsErrorEvent < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- reversible do |dir|
6
- dir.up do
7
- # Ensure this incremental update migration is idempotent
8
- # with monolithic install migration.
9
- return if connection.column_exists?(:good_jobs, :error_event)
10
- end
11
- end
12
-
13
- add_column :good_jobs, :error_event, :integer, limit: 2
14
- add_column :good_job_executions, :error_event, :integer, limit: 2
15
- end
16
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class RecreateGoodJobCronIndexesWithConditional < ActiveRecord::Migration<%= migration_version %>
4
- disable_ddl_transaction!
5
-
6
- def change
7
- reversible do |dir|
8
- dir.up do
9
- unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at_cond)
10
- add_index :good_jobs, [:cron_key, :created_at], where: "(cron_key IS NOT NULL)",
11
- name: :index_good_jobs_on_cron_key_and_created_at_cond, algorithm: :concurrently
12
- end
13
- unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at_cond)
14
- add_index :good_jobs, [:cron_key, :cron_at], where: "(cron_key IS NOT NULL)", unique: true,
15
- name: :index_good_jobs_on_cron_key_and_cron_at_cond, algorithm: :concurrently
16
- end
17
-
18
- if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at)
19
- remove_index :good_jobs, name: :index_good_jobs_on_cron_key_and_created_at
20
- end
21
- if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at)
22
- remove_index :good_jobs, name: :index_good_jobs_on_cron_key_and_cron_at
23
- end
24
- end
25
-
26
- dir.down do
27
- unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at)
28
- add_index :good_jobs, [:cron_key, :created_at],
29
- name: :index_good_jobs_on_cron_key_and_created_at, algorithm: :concurrently
30
- end
31
- unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at)
32
- add_index :good_jobs, [:cron_key, :cron_at], unique: true,
33
- name: :index_good_jobs_on_cron_key_and_cron_at, algorithm: :concurrently
34
- end
35
-
36
- if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_created_at_cond)
37
- remove_index :good_jobs, name: :index_good_jobs_on_cron_key_and_created_at_cond
38
- end
39
- if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_cron_key_and_cron_at_cond)
40
- remove_index :good_jobs, name: :index_good_jobs_on_cron_key_and_cron_at_cond
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobLabels < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- reversible do |dir|
6
- dir.up do
7
- # Ensure this incremental update migration is idempotent
8
- # with monolithic install migration.
9
- return if connection.column_exists?(:good_jobs, :labels)
10
- end
11
- end
12
-
13
- add_column :good_jobs, :labels, :text, array: true
14
- end
15
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobLabelsIndex < ActiveRecord::Migration<%= migration_version %>
4
- disable_ddl_transaction!
5
-
6
- def change
7
- reversible do |dir|
8
- dir.up do
9
- unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_labels)
10
- add_index :good_jobs, :labels, using: :gin, where: "(labels IS NOT NULL)",
11
- name: :index_good_jobs_on_labels, algorithm: :concurrently
12
- end
13
- end
14
-
15
- dir.down do
16
- if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_labels)
17
- remove_index :good_jobs, name: :index_good_jobs_on_labels
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class RemoveGoodJobActiveIdIndex < ActiveRecord::Migration<%= migration_version %>
4
- disable_ddl_transaction!
5
-
6
- def change
7
- reversible do |dir|
8
- dir.up do
9
- if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id)
10
- remove_index :good_jobs, name: :index_good_jobs_on_active_job_id
11
- end
12
- end
13
-
14
- dir.down do
15
- unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id)
16
- add_index :good_jobs, :active_job_id, name: :index_good_jobs_on_active_job_id
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateIndexGoodJobJobsForCandidateLookup < ActiveRecord::Migration<%= migration_version %>
4
- disable_ddl_transaction!
5
-
6
- def change
7
- reversible do |dir|
8
- dir.up do
9
- # Ensure this incremental update migration is idempotent
10
- # with monolithic install migration.
11
- return if connection.index_name_exists?(:good_jobs, :index_good_job_jobs_for_candidate_lookup)
12
- end
13
- end
14
-
15
- add_index :good_jobs, [:priority, :created_at], order: { priority: "ASC NULLS LAST", created_at: :asc },
16
- where: "finished_at IS NULL", name: :index_good_job_jobs_for_candidate_lookup,
17
- algorithm: :concurrently
18
- end
19
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobExecutionErrorBacktrace < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- reversible do |dir|
6
- dir.up do
7
- # Ensure this incremental update migration is idempotent
8
- # with monolithic install migration.
9
- return if connection.column_exists?(:good_job_executions, :error_backtrace)
10
- end
11
- end
12
-
13
- add_column :good_job_executions, :error_backtrace, :text, array: true
14
- end
15
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobProcessLockIds < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- reversible do |dir|
6
- dir.up do
7
- # Ensure this incremental update migration is idempotent
8
- # with monolithic install migration.
9
- return if connection.column_exists?(:good_jobs, :locked_by_id)
10
- end
11
- end
12
-
13
- add_column :good_jobs, :locked_by_id, :uuid
14
- add_column :good_jobs, :locked_at, :datetime
15
- add_column :good_job_executions, :process_id, :uuid
16
- add_column :good_job_processes, :lock_type, :integer, limit: 2
17
- end
18
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobProcessLockIndexes < ActiveRecord::Migration<%= migration_version %>
4
- disable_ddl_transaction!
5
-
6
- def change
7
- reversible do |dir|
8
- dir.up do
9
- unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_priority_scheduled_at_unfinished_unlocked)
10
- add_index :good_jobs, [:priority, :scheduled_at],
11
- order: { priority: "ASC NULLS LAST", scheduled_at: :asc },
12
- where: "finished_at IS NULL AND locked_by_id IS NULL",
13
- name: :index_good_jobs_on_priority_scheduled_at_unfinished_unlocked,
14
- algorithm: :concurrently
15
- end
16
-
17
- unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_locked_by_id)
18
- add_index :good_jobs, :locked_by_id,
19
- where: "locked_by_id IS NOT NULL",
20
- name: :index_good_jobs_on_locked_by_id,
21
- algorithm: :concurrently
22
- end
23
-
24
- unless connection.index_name_exists?(:good_job_executions, :index_good_job_executions_on_process_id_and_created_at)
25
- add_index :good_job_executions, [:process_id, :created_at],
26
- name: :index_good_job_executions_on_process_id_and_created_at,
27
- algorithm: :concurrently
28
- end
29
- end
30
-
31
- dir.down do
32
- remove_index(:good_jobs, name: :index_good_jobs_on_priority_scheduled_at_unfinished_unlocked) if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_priority_scheduled_at_unfinished_unlocked)
33
- remove_index(:good_jobs, name: :index_good_jobs_on_locked_by_id) if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_locked_by_id)
34
- remove_index(:good_job_executions, name: :index_good_job_executions_on_process_id_and_created_at) if connection.index_name_exists?(:good_job_executions, :index_good_job_executions_on_process_id_and_created_at)
35
- end
36
- end
37
- end
38
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateGoodJobExecutionDuration < ActiveRecord::Migration<%= migration_version %>
4
- def change
5
- reversible do |dir|
6
- dir.up do
7
- # Ensure this incremental update migration is idempotent
8
- # with monolithic install migration.
9
- return if connection.column_exists?(:good_job_executions, :duration)
10
- end
11
- end
12
-
13
- add_column :good_job_executions, :duration, :interval
14
- end
15
- end