ductwork 0.25.0 → 1.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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/audit-clock-drift/SKILL.md +11 -0
  3. data/.claude/skills/audit-database-indexes/SKILL.md +11 -0
  4. data/.claude/skills/audit-database-support/SKILL.md +18 -0
  5. data/.claude/skills/audit-durability/SKILL.md +17 -0
  6. data/.saturnci/database.yml +1 -0
  7. data/CHANGELOG-PRO.md +72 -0
  8. data/CHANGELOG.md +148 -1
  9. data/CLAUDE.md +34 -0
  10. data/README.md +24 -14
  11. data/app/controllers/ductwork/application_controller.rb +3 -3
  12. data/app/controllers/ductwork/dashboards_controller.rb +1 -1
  13. data/app/controllers/ductwork/pipelines_controller.rb +4 -3
  14. data/app/helpers/ductwork/application_helper.rb +2 -2
  15. data/app/views/ductwork/dashboards/show.html.erb +12 -12
  16. data/app/views/ductwork/pipelines/index.html.erb +12 -12
  17. data/app/views/ductwork/pipelines/show.html.erb +13 -13
  18. data/app/views/ductwork/step_errors/index.html.erb +2 -2
  19. data/lib/ductwork/branch_claim.rb +185 -0
  20. data/lib/ductwork/cli.rb +73 -24
  21. data/lib/ductwork/configuration.rb +73 -3
  22. data/lib/ductwork/context.rb +17 -19
  23. data/lib/ductwork/database_clock.rb +84 -0
  24. data/lib/ductwork/dsl/branch_builder.rb +46 -1
  25. data/lib/ductwork/dsl/definition_builder.rb +101 -2
  26. data/lib/ductwork/{job_claim.rb → execution_claim.rb} +7 -6
  27. data/lib/ductwork/fault_injection.rb +35 -0
  28. data/lib/ductwork/migration_helper.rb +1 -1
  29. data/lib/ductwork/models/advancement.rb +48 -0
  30. data/lib/ductwork/models/attempt.rb +9 -0
  31. data/lib/ductwork/models/availability.rb +2 -0
  32. data/lib/ductwork/models/branch.rb +800 -0
  33. data/lib/ductwork/models/branch_link.rb +10 -0
  34. data/lib/ductwork/models/execution.rb +199 -2
  35. data/lib/ductwork/models/job.rb +8 -121
  36. data/lib/ductwork/models/pipeline.rb +152 -255
  37. data/lib/ductwork/models/process.rb +177 -5
  38. data/lib/ductwork/models/result.rb +2 -1
  39. data/lib/ductwork/models/run.rb +119 -1
  40. data/lib/ductwork/models/step.rb +26 -6
  41. data/lib/ductwork/models/transition.rb +15 -0
  42. data/lib/ductwork/models/tuple.rb +1 -4
  43. data/lib/ductwork/models/workflow.rb +3 -0
  44. data/lib/ductwork/optimistic_locking_execution_claim.rb +97 -0
  45. data/lib/ductwork/processes/health_check.rb +87 -0
  46. data/lib/ductwork/processes/job_worker.rb +86 -20
  47. data/lib/ductwork/processes/job_worker_runner.rb +25 -37
  48. data/lib/ductwork/processes/pipeline_advancer.rb +48 -76
  49. data/lib/ductwork/processes/pipeline_advancer_runner.rb +34 -44
  50. data/lib/ductwork/processes/process_supervisor.rb +87 -10
  51. data/lib/ductwork/processes/thread_supervisor.rb +55 -21
  52. data/lib/ductwork/processes/thread_supervisor_runner.rb +8 -5
  53. data/lib/ductwork/processes/worker_health_check.rb +55 -0
  54. data/lib/ductwork/row_locking_execution_claim.rb +77 -0
  55. data/lib/ductwork/testing/rspec.rb +28 -11
  56. data/lib/ductwork/version.rb +1 -1
  57. data/lib/ductwork.rb +5 -0
  58. data/lib/generators/ductwork/install/install_generator.rb +14 -4
  59. data/lib/generators/ductwork/install/templates/config/ductwork.yml +4 -0
  60. data/lib/generators/ductwork/install/templates/db/create_ductwork_advancements.rb +29 -0
  61. data/lib/generators/ductwork/install/templates/db/create_ductwork_attempts.rb +20 -0
  62. data/lib/generators/ductwork/install/templates/db/create_ductwork_availabilities.rb +18 -5
  63. data/lib/generators/ductwork/install/templates/db/create_ductwork_branch_links.rb +27 -0
  64. data/lib/generators/ductwork/install/templates/db/create_ductwork_branches.rb +37 -0
  65. data/lib/generators/ductwork/install/templates/db/create_ductwork_executions.rb +8 -1
  66. data/lib/generators/ductwork/install/templates/db/create_ductwork_pipelines.rb +0 -8
  67. data/lib/generators/ductwork/install/templates/db/create_ductwork_processes.rb +2 -0
  68. data/lib/generators/ductwork/install/templates/db/create_ductwork_results.rb +1 -0
  69. data/lib/generators/ductwork/install/templates/db/create_ductwork_runs.rb +45 -6
  70. data/lib/generators/ductwork/install/templates/db/create_ductwork_steps.rb +20 -5
  71. data/lib/generators/ductwork/install/templates/db/create_ductwork_transitions.rb +43 -0
  72. data/lib/generators/ductwork/install/templates/db/create_ductwork_tuples.rb +3 -3
  73. data/lib/generators/ductwork/update/templates/db/add_crash_count_to_ductwork_advancements.rb +7 -0
  74. data/lib/generators/ductwork/update/templates/db/add_crash_count_to_ductwork_executions.rb +14 -0
  75. data/lib/generators/ductwork/update/templates/db/add_indexes_to_ductwork_results.rb +7 -0
  76. data/lib/generators/ductwork/update/templates/db/add_indexes_to_ductwork_runs.rb +9 -0
  77. data/lib/generators/ductwork/update/templates/db/add_indexes_to_ductwork_transitions.rb +16 -0
  78. data/lib/generators/ductwork/update/templates/db/add_pipeline_started_index_to_ductwork_runs.rb +7 -0
  79. data/lib/generators/ductwork/update/templates/db/add_process_id_to_ductwork_executions.rb +35 -0
  80. data/lib/generators/ductwork/update/templates/db/add_role_to_ductwork_processes.rb +20 -0
  81. data/lib/generators/ductwork/update/templates/db/associate_branches_to_runs.rb +74 -0
  82. data/lib/generators/ductwork/update/templates/db/associate_steps_to_branches.rb +24 -0
  83. data/lib/generators/ductwork/update/templates/db/associate_steps_to_runs.rb +72 -0
  84. data/lib/generators/ductwork/update/templates/db/associate_tuples_to_runs.rb +73 -0
  85. data/lib/generators/ductwork/update/templates/db/backfill_branch_ids_on_steps.rb +21 -0
  86. data/lib/generators/ductwork/update/templates/db/create_ductwork_advancements.rb +28 -0
  87. data/lib/generators/ductwork/update/templates/db/create_ductwork_branch_links.rb +27 -0
  88. data/lib/generators/ductwork/update/templates/db/create_ductwork_branches.rb +37 -0
  89. data/lib/generators/ductwork/update/templates/db/create_ductwork_runs.rb +55 -0
  90. data/lib/generators/ductwork/update/templates/db/create_ductwork_transitions.rb +32 -0
  91. data/lib/generators/ductwork/update/templates/db/denormalize_pipeline_klass_on_availabilities.rb +11 -4
  92. data/lib/generators/ductwork/update/templates/db/migrate_tables_to_uuid_primary_key.rb +5 -0
  93. data/lib/generators/ductwork/update/templates/db/rename_runs_to_attempts.rb +7 -0
  94. data/lib/generators/ductwork/update/templates/db/update_process_associations.rb +29 -0
  95. data/lib/generators/ductwork/update/update_generator.rb +99 -0
  96. metadata +47 -6
  97. data/lib/ductwork/optimistic_locking_job_claim.rb +0 -88
  98. data/lib/ductwork/row_locking_job_claim.rb +0 -75
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddPipelineStartedIndexToDuctworkRuns < Ductwork::Migration
4
+ def change
5
+ add_index :ductwork_runs, %i[pipeline_id started_at]
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddProcessIdToDuctworkExecution < Ductwork::Migration
4
+ def up
5
+ options = if postgresql?
6
+ {
7
+ type: uuid_column_type,
8
+ index: true,
9
+ null: true,
10
+ foreign_key: { to_table: :ductwork_processes },
11
+ }
12
+ else
13
+ {
14
+ type: uuid_column_type,
15
+ limit: 36,
16
+ index: true,
17
+ null: true,
18
+ foreign_key: { to_table: :ductwork_processes },
19
+ }
20
+ end
21
+
22
+ add_reference :ductwork_executions, :process, **options
23
+
24
+ Ductwork::Execution.find_each do |execution|
25
+ execution.update!(process: execution.availability.process)
26
+ end
27
+ end
28
+
29
+ def down
30
+ remove_reference :ductwork_executions,
31
+ :process,
32
+ foreign_key: { to_table: :ductwork_processes },
33
+ index: true
34
+ end
35
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddRoleToDuctworkProcesses < Ductwork::Migration
4
+ def up
5
+ add_column :ductwork_processes, :role, :string
6
+
7
+ # NOTE: ideally there are no process records that exist because the
8
+ # ductwork process should not be running. either way, we explicitly
9
+ # don't set it to supervisor so it won't report in the health checks
10
+ Ductwork::Process
11
+ .where(role: nil)
12
+ .update_all(role: "pipeline_advancer")
13
+
14
+ change_column_null :ductwork_executions, :crash_count, false
15
+ end
16
+
17
+ def down
18
+ remove_column :ductwork_processes, :role, :string
19
+ end
20
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AssociateBranchesToRuns < Ductwork::Migration
4
+ def up
5
+ options = if postgresql?
6
+ {
7
+ type: uuid_column_type,
8
+ index: true,
9
+ null: true,
10
+ foreign_key: { to_table: :ductwork_runs },
11
+ }
12
+ else
13
+ {
14
+ type: uuid_column_type,
15
+ limit: 36,
16
+ index: true,
17
+ null: true,
18
+ foreign_key: { to_table: :ductwork_runs },
19
+ }
20
+ end
21
+
22
+ add_reference :ductwork_branches, :run, **options
23
+
24
+ Ductwork::Pipeline.find_each do |pipeline|
25
+ run = Ductwork::Run.create!(
26
+ pipeline: pipeline,
27
+ pipeline_klass: pipeline.klass,
28
+ definition: pipeline.definition,
29
+ definition_sha1: pipeline.definition_sha1,
30
+ status: pipeline.status,
31
+ triggered_at: pipeline.triggered_at,
32
+ started_at: pipeline.started_at,
33
+ completed_at: pipeline.completed_at,
34
+ halted_at: pipeline.halted_at
35
+ )
36
+ pipeline.branches.update_all(run_id: run.id)
37
+ end
38
+
39
+ remove_index :ductwork_branches, %w[pipeline_id started_at]
40
+ remove_reference :ductwork_branches, :pipeline, index: true, foreign_key: { to_table: :ductwork_pipelines }
41
+
42
+ add_index :ductwork_branches, %w[run_id started_at]
43
+ end
44
+
45
+ def down
46
+ options = if postgresql?
47
+ {
48
+ type: uuid_column_type,
49
+ index: true,
50
+ null: true,
51
+ foreign_key: { to_table: :ductwork_pipelines },
52
+ }
53
+ else
54
+ {
55
+ type: uuid_column_type,
56
+ limit: 36,
57
+ index: true,
58
+ null: true,
59
+ foreign_key: { to_table: :ductwork_pipelines },
60
+ }
61
+ end
62
+
63
+ add_reference :ductwork_branches, :pipeline, **options
64
+
65
+ Ductwork::Run.find_each do |run|
66
+ Ductwork::Branch.where(run_id: run.id).update_all(pipeline_id: run.pipeline_id)
67
+ end
68
+
69
+ remove_index :ductwork_branches, %w[run_id started_at]
70
+ remove_reference :ductwork_branches, :run, index: true, foreign_key: { to_table: :ductwork_runs }
71
+
72
+ add_index :ductwork_branches, %w[pipeline_id started_at]
73
+ end
74
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AssociateStepsToBranches < Ductwork::Migration
4
+ def change
5
+ options = if postgresql?
6
+ {
7
+ type: uuid_column_type,
8
+ index: true,
9
+ null: true,
10
+ foreign_key: { to_table: :ductwork_branches },
11
+ }
12
+ else
13
+ {
14
+ type: uuid_column_type,
15
+ limit: 36,
16
+ index: true,
17
+ null: true,
18
+ foreign_key: { to_table: :ductwork_branches },
19
+ }
20
+ end
21
+
22
+ add_reference :ductwork_steps, :branch, **options
23
+ end
24
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AssociateStepsToRuns < Ductwork::Migration
4
+ def up
5
+ options = if postgresql?
6
+ {
7
+ type: uuid_column_type,
8
+ index: true,
9
+ null: true,
10
+ foreign_key: { to_table: :ductwork_runs },
11
+ }
12
+ else
13
+ {
14
+ type: uuid_column_type,
15
+ limit: 36,
16
+ index: true,
17
+ null: true,
18
+ foreign_key: { to_table: :ductwork_runs },
19
+ }
20
+ end
21
+
22
+ add_reference :ductwork_steps, :run, **options
23
+
24
+ Ductwork::Pipeline.find_each do |pipeline|
25
+ run = Ductwork::Run.find_by(pipeline_id: pipeline.id)
26
+ pipeline.steps.update_all(run_id: run.id) if run
27
+ end
28
+
29
+ remove_index :ductwork_steps, %i[pipeline_id status node]
30
+ remove_index :ductwork_steps, %i[pipeline_id node status]
31
+ remove_index :ductwork_steps, %i[pipeline_id status]
32
+ remove_reference :ductwork_steps, :pipeline, index: true, foreign_key: { to_table: :ductwork_pipelines }
33
+
34
+ add_index :ductwork_steps, %i[run_id status node]
35
+ add_index :ductwork_steps, %i[run_id node status]
36
+ add_index :ductwork_steps, %i[run_id status]
37
+ end
38
+
39
+ def down
40
+ options = if postgresql?
41
+ {
42
+ type: uuid_column_type,
43
+ index: true,
44
+ null: true,
45
+ foreign_key: { to_table: :ductwork_pipelines },
46
+ }
47
+ else
48
+ {
49
+ type: uuid_column_type,
50
+ limit: 36,
51
+ index: true,
52
+ null: true,
53
+ foreign_key: { to_table: :ductwork_pipelines },
54
+ }
55
+ end
56
+
57
+ add_reference :ductwork_steps, :pipeline, **options
58
+
59
+ Ductwork::Run.find_each do |run|
60
+ Ductwork::Step.where(run_id: run.id).update_all(pipeline_id: run.pipeline_id)
61
+ end
62
+
63
+ remove_index :ductwork_steps, %i[run_id status node]
64
+ remove_index :ductwork_steps, %i[run_id node status]
65
+ remove_index :ductwork_steps, %i[run_id status]
66
+ remove_reference :ductwork_steps, :run, index: true, foreign_key: { to_table: :ductwork_runs }
67
+
68
+ add_index :ductwork_steps, %i[pipeline_id status node]
69
+ add_index :ductwork_steps, %i[pipeline_id node status]
70
+ add_index :ductwork_steps, %i[pipeline_id status]
71
+ end
72
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AssociateTuplesToRuns < Ductwork::Migration
4
+ def up
5
+ options = if postgresql?
6
+ {
7
+ type: uuid_column_type,
8
+ index: true,
9
+ null: true,
10
+ foreign_key: { to_table: :ductwork_runs },
11
+ }
12
+ else
13
+ {
14
+ type: uuid_column_type,
15
+ limit: 36,
16
+ index: true,
17
+ null: true,
18
+ foreign_key: { to_table: :ductwork_runs },
19
+ }
20
+ end
21
+
22
+ add_reference :ductwork_tuples, :run, **options
23
+
24
+ Ductwork::Pipeline.find_each do |pipeline|
25
+ run = Ductwork::Run.find_by(pipeline_id: pipeline.id)
26
+
27
+ pipeline.tuples.update_all(run_id: run.id) if run
28
+ end
29
+
30
+ remove_index :ductwork_tuples, %i[pipeline_id status node]
31
+ remove_index :ductwork_tuples, %i[pipeline_id node status]
32
+ remove_index :ductwork_tuples, %i[pipeline_id status]
33
+ remove_reference :ductwork_tuples, :pipeline, index: true, foreign_key: { to_table: :ductwork_pipelines }
34
+
35
+ add_index :ductwork_tuples, %i[run_id status node]
36
+ add_index :ductwork_tuples, %i[run_id node status]
37
+ add_index :ductwork_tuples, %i[run_id status]
38
+ end
39
+
40
+ def down
41
+ options = if postgresql?
42
+ {
43
+ type: uuid_column_type,
44
+ index: true,
45
+ null: true,
46
+ foreign_key: { to_table: :ductwork_pipelines },
47
+ }
48
+ else
49
+ {
50
+ type: uuid_column_type,
51
+ limit: 36,
52
+ index: true,
53
+ null: true,
54
+ foreign_key: { to_table: :ductwork_pipelines },
55
+ }
56
+ end
57
+
58
+ add_reference :ductwork_tuples, :pipeline, **options
59
+
60
+ Ductwork::Run.find_each do |run|
61
+ Ductwork::Tuple.where(run_id: run.id).update_all(pipeline_id: run.pipeline_id)
62
+ end
63
+
64
+ remove_index :ductwork_tuples, %i[run_id status node]
65
+ remove_index :ductwork_tuples, %i[run_id node status]
66
+ remove_index :ductwork_tuples, %i[run_id status]
67
+ remove_reference :ductwork_tuples, :run, index: true, foreign_key: { to_table: :ductwork_runs }
68
+
69
+ add_index :ductwork_tuples, %i[pipeline_id status node]
70
+ add_index :ductwork_tuples, %i[pipeline_id node status]
71
+ add_index :ductwork_tuples, %i[pipeline_id status]
72
+ end
73
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BackfillBranchIdsOnSteps < Ductwork::Migration
4
+ def up
5
+ Ductwork::Pipeline.find_each do |pipeline|
6
+ branch = Ductwork::Branch.create!(
7
+ pipeline: pipeline,
8
+ pipeline_klass: pipeline.klass,
9
+ status: pipeline.status,
10
+ started_at: pipeline.started_at,
11
+ last_advanced_at: pipeline.last_advanced_at,
12
+ completed_at: pipeline.completed_at
13
+ )
14
+ pipeline.steps.update_all(branch_id: branch.id)
15
+ end
16
+ end
17
+
18
+ def down
19
+ Ductwork::Step.update_all(branch_id: nil)
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDuctworkAdvancements < Ductwork::Migration
4
+ def change
5
+ create_ductwork_table :ductwork_advancements do |table|
6
+ belongs_to(
7
+ table,
8
+ :process,
9
+ index: true,
10
+ null: true,
11
+ foreign_key: { to_table: :ductwork_processes }
12
+ )
13
+ belongs_to(
14
+ table,
15
+ :transition,
16
+ index: true,
17
+ null: false,
18
+ foreign_key: { to_table: :ductwork_transitions }
19
+ )
20
+ table.datetime :started_at, null: false
21
+ table.datetime :completed_at
22
+ table.string :error_klass
23
+ table.string :error_message
24
+ table.text :error_backtrace
25
+ table.timestamps null: false
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDuctworkBranchLinks < Ductwork::Migration
4
+ def change
5
+ create_ductwork_table :ductwork_branch_links do |table|
6
+ belongs_to(
7
+ table,
8
+ :parent_branch,
9
+ index: true,
10
+ null: false,
11
+ foreign_key: { to_table: :ductwork_branches }
12
+ )
13
+ belongs_to(
14
+ table,
15
+ :child_branch,
16
+ index: true,
17
+ null: false,
18
+ foreign_key: { to_table: :ductwork_branches }
19
+ )
20
+ table.timestamps null: false
21
+ end
22
+
23
+ add_index :ductwork_branch_links,
24
+ %w[parent_branch_id child_branch_id],
25
+ unique: true
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDuctworkBranches < Ductwork::Migration
4
+ def change
5
+ create_ductwork_table :ductwork_branches do |table|
6
+ belongs_to(
7
+ table,
8
+ :pipeline,
9
+ index: true,
10
+ null: false,
11
+ foreign_key: { to_table: :ductwork_pipelines }
12
+ )
13
+ table.string :pipeline_klass, null: false
14
+ table.string :status, null: false
15
+ table.string :halt_reason
16
+ table.string :claim_token
17
+ table.datetime :claimed_for_advancing_at
18
+ table.datetime :last_advanced_at, null: false
19
+ table.datetime :started_at, null: false
20
+ table.datetime :completed_at
21
+ table.timestamps null: false
22
+ end
23
+
24
+ if mysql?
25
+ add_index :ductwork_branches,
26
+ %w[pipeline_klass status claimed_for_advancing_at last_advanced_at],
27
+ name: "index_ductwork_branches_on_claim_latest"
28
+ else
29
+ add_index :ductwork_branches,
30
+ %w[pipeline_klass status last_advanced_at],
31
+ where: "claimed_for_advancing_at IS NULL",
32
+ name: "index_ductwork_branches_on_claim_latest"
33
+ end
34
+ add_index :ductwork_branches, %w[pipeline_id started_at]
35
+ add_index :ductwork_branches, %w[run_id status]
36
+ end
37
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDuctworkRuns < Ductwork::Migration
4
+ def change
5
+ create_ductwork_table :ductwork_runs do |table|
6
+ belongs_to(
7
+ table,
8
+ :pipeline,
9
+ index: true,
10
+ null: false,
11
+ foreign_key: { to_table: :ductwork_pipelines }
12
+ )
13
+ table.string :pipeline_klass, null: false
14
+ table.text :definition, null: false
15
+ table.string :definition_sha1, null: false
16
+ table.string :status, null: false
17
+ table.datetime :triggered_at, null: false
18
+ table.datetime :started_at, null: false
19
+ table.datetime :completed_at
20
+ table.datetime :halted_at
21
+ table.datetime :on_halt_dispatched_at
22
+ table.timestamps null: false
23
+ end
24
+
25
+ add_index :ductwork_runs, %i[pipeline_id status]
26
+
27
+ if mysql?
28
+ reversible do |direction|
29
+ direction.up do
30
+ execute <<~SQL
31
+ ALTER TABLE ductwork_runs
32
+ ADD COLUMN active_pipeline_id VARCHAR(36)
33
+ GENERATED ALWAYS AS (
34
+ IF(status IN ('in_progress', 'paused'), pipeline_id, NULL)
35
+ )
36
+ SQL
37
+ add_index :ductwork_runs, :active_pipeline_id,
38
+ unique: true,
39
+ name: :idx_unique_active_run
40
+ end
41
+
42
+ direction.down do
43
+ remove_index :ductwork_runs, name: :idx_unique_active_run
44
+ remove_column :ductwork_runs, :active_pipeline_id
45
+ end
46
+ end
47
+ else
48
+ add_index :ductwork_runs,
49
+ :pipeline_id,
50
+ unique: true,
51
+ where: "status IN ('in_progress', 'paused')",
52
+ name: :idx_unique_active_run
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDuctworkTransitions < Ductwork::Migration
4
+ def change
5
+ create_ductwork_table :ductwork_transitions do |table|
6
+ belongs_to(
7
+ table,
8
+ :branches,
9
+ index: true,
10
+ null: false,
11
+ foreign_key: { to_table: :ductwork_branches }
12
+ )
13
+ belongs_to(
14
+ table,
15
+ :in_step,
16
+ index: true,
17
+ null: false,
18
+ foreign_key: { to_table: :ductwork_steps }
19
+ )
20
+ belongs_to(
21
+ table,
22
+ :out_step,
23
+ index: true,
24
+ null: true,
25
+ foreign_key: { to_table: :ductwork_steps }
26
+ )
27
+ table.datetime :started_at, null: false
28
+ table.datetime :completed_at
29
+ table.timestamps null: false
30
+ end
31
+ end
32
+ end
@@ -12,9 +12,16 @@ class DenormalizePipelineKlassOnAvailabilities < Ductwork::Migration
12
12
 
13
13
  change_column_null :ductwork_availabilities, :pipeline_klass, false
14
14
  remove_index :ductwork_availabilities, name: "index_ductwork_availabilities_on_claim_latest"
15
- add_index :ductwork_availabilities,
16
- %i[pipeline_klass started_at],
17
- name: "index_ductwork_availabilities_on_claim_latest",
18
- where: "completed_at IS NULL"
15
+
16
+ if mysql?
17
+ add_index :ductwork_availabilities,
18
+ %i[pipeline_klass completed_at started_at],
19
+ name: "index_ductwork_availabilities_on_claim_latest"
20
+ else
21
+ add_index :ductwork_availabilities,
22
+ %i[pipeline_klass started_at],
23
+ name: "index_ductwork_availabilities_on_claim_latest",
24
+ where: "completed_at IS NULL"
25
+ end
19
26
  end
20
27
  end
@@ -31,6 +31,7 @@ class MigrateTablesToUuidPrimaryKey < Ductwork::Migration
31
31
  drop_old_foreign_keys
32
32
  swap_primary_keys
33
33
  swap_foreign_keys
34
+ create_missing_indexes
34
35
  end
35
36
 
36
37
  def down
@@ -115,4 +116,8 @@ class MigrateTablesToUuidPrimaryKey < Ductwork::Migration
115
116
  end
116
117
  end
117
118
  end
119
+
120
+ def create_missing_indexes
121
+ add_index :ductwork_tuples, %i[key pipeline_id], unique: true
122
+ end
118
123
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RenameRunsToAttempts < Ductwork::Migration
4
+ def change
5
+ rename_table :ductwork_runs, :ductwork_attempts
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UpdateProcessAssociations < Ductwork::Migration
4
+ def change
5
+ remove_column :ductwork_availabilities, :process_id, :integer
6
+
7
+ options = if postgresql?
8
+ {
9
+ type: uuid_column_type,
10
+ index: true,
11
+ null: true,
12
+ foreign_key: { to_table: :ductwork_processes },
13
+ }
14
+ else
15
+ {
16
+ type: uuid_column_type,
17
+ limit: 36,
18
+ index: true,
19
+ null: true,
20
+ foreign_key: { to_table: :ductwork_processes },
21
+ }
22
+ end
23
+
24
+ add_reference :ductwork_availabilities, :process, **options
25
+ add_index :ductwork_availabilities, %i[id process_id]
26
+
27
+ remove_column :ductwork_executions, :process_id, :integer
28
+ end
29
+ end