good_job 3.99.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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