ductwork 0.26.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 +60 -0
  8. data/CHANGELOG.md +144 -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 +6 -1
  25. data/lib/ductwork/dsl/definition_builder.rb +24 -1
  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 +150 -272
  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,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
@@ -10,6 +10,8 @@ module Ductwork
10
10
  source_root File.expand_path("templates", __dir__)
11
11
 
12
12
  def create_files
13
+ connection = Ductwork::Record.connection
14
+
13
15
  if Ductwork::Availability.column_names.exclude?("pipeline_klass")
14
16
  migration_template "db/denormalize_pipeline_klass_on_availabilities.rb",
15
17
  "db/migrate/denormalize_pipeline_klass_on_availabilities.rb"
@@ -19,6 +21,103 @@ module Ductwork
19
21
  migration_template "db/migrate_tables_to_uuid_primary_key.rb",
20
22
  "db/migrate/migrate_tables_to_uuid_primary_key.rb"
21
23
  end
24
+
25
+ if !connection.table_exists?(:ductwork_branches)
26
+ migration_template "db/create_ductwork_branches.rb",
27
+ "db/migrate/create_ductwork_branches.rb"
28
+ end
29
+
30
+ if !connection.table_exists?(:ductwork_branch_links)
31
+ migration_template "db/create_ductwork_branch_links.rb",
32
+ "db/migrate/create_ductwork_branch_links.rb"
33
+ end
34
+
35
+ if Ductwork::Step.column_names.exclude?("branch_id")
36
+ migration_template "db/associate_steps_to_branches.rb",
37
+ "db/migrate/associate_steps_to_branches.rb"
38
+ migration_template "db/backfill_branch_ids_on_steps.rb",
39
+ "db/migrate/backfill_branch_ids_on_steps.rb"
40
+ end
41
+
42
+ if !connection.table_exists?(:ductwork_transitions)
43
+ migration_template "db/create_ductwork_transitions.rb",
44
+ "db/migrate/create_ductwork_transitions.rb"
45
+ end
46
+
47
+ if !connection.table_exists?(:ductwork_advancements)
48
+ migration_template "db/create_ductwork_advancements.rb",
49
+ "db/migrate/create_ductwork_advancements.rb"
50
+ end
51
+
52
+ if Ductwork::Execution.column_names.include?("process_id")
53
+ migration_template "db/update_process_associations.rb",
54
+ "db/migrate/update_process_associations.rb"
55
+ end
56
+
57
+ if connection.table_exists?(:ductwork_runs)
58
+ migration_template "db/rename_runs_to_attempts.rb",
59
+ "db/migrate/rename_runs_to_attempts.rb"
60
+ end
61
+
62
+ if !connection.table_exists?(:ductwork_runs)
63
+ migration_template "db/create_ductwork_runs.rb",
64
+ "db/migrate/create_ductwork_runs.rb"
65
+ end
66
+
67
+ if Ductwork::Branch.column_names.include?("pipeline_id")
68
+ migration_template "db/associate_branches_to_runs.rb",
69
+ "db/migrate/associate_branches_to_runs.rb"
70
+ end
71
+
72
+ if Ductwork::Step.column_names.include?("pipeline_id")
73
+ migration_template "db/associate_steps_to_runs.rb",
74
+ "db/migrate/associate_steps_to_runs.rb"
75
+ end
76
+
77
+ if Ductwork::Tuple.column_names.include?("pipeline_id")
78
+ migration_template "db/associate_tuples_to_runs.rb",
79
+ "db/migrate/associate_tuples_to_runs.rb"
80
+ end
81
+
82
+ if Ductwork::Execution.column_names.exclude?("crash_count")
83
+ migration_template "db/add_crash_count_to_ductwork_executions.rb",
84
+ "db/migrate/add_crash_count_to_ductwork_executions.rb"
85
+ end
86
+
87
+ if Ductwork::Advancement.column_names.exclude?("crash_count")
88
+ migration_template "db/add_crash_count_to_ductwork_advancements.rb",
89
+ "db/migrate/add_crash_count_to_ductwork_advancements.rb"
90
+ end
91
+
92
+ if Ductwork::Execution.column_names.exclude?("process_id")
93
+ migration_template "db/add_process_id_to_ductwork_executions.rb",
94
+ "db/migrate/add_process_id_to_ductwork_executions.rb"
95
+ end
96
+
97
+ if Ductwork::Process.column_names.exclude?("role")
98
+ migration_template "db/add_role_to_ductwork_processes.rb",
99
+ "db/migrate/add_role_to_ductwork_processes.rb"
100
+ end
101
+
102
+ if !connection.index_exists?(:ductwork_results, %i[result_type created_at])
103
+ migration_template "db/add_indexes_to_ductwork_results.rb",
104
+ "db/migrate/add_indexes_to_ductwork_results.rb"
105
+ end
106
+
107
+ if !connection.index_exists?(:ductwork_runs, :started_at)
108
+ migration_template "db/add_indexes_to_ductwork_runs.rb",
109
+ "db/migrate/add_indexes_to_ductwork_runs.rb"
110
+ end
111
+
112
+ if !connection.index_exists?(:ductwork_runs, %i[pipeline_id started_at])
113
+ migration_template "db/add_pipeline_started_index_to_ductwork_runs.rb",
114
+ "db/migrate/add_pipeline_started_index_to_ductwork_runs.rb"
115
+ end
116
+
117
+ if !connection.index_exists?(:ductwork_transitions, name: "index_ductwork_transitions_on_latest_open")
118
+ migration_template "db/add_indexes_to_ductwork_transitions.rb",
119
+ "db/migrate/add_indexes_to_ductwork_transitions.rb"
120
+ end
22
121
  end
23
122
  end
24
123
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ductwork
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Ewing
@@ -111,12 +111,17 @@ executables: []
111
111
  extensions: []
112
112
  extra_rdoc_files: []
113
113
  files:
114
+ - ".claude/skills/audit-clock-drift/SKILL.md"
115
+ - ".claude/skills/audit-database-indexes/SKILL.md"
116
+ - ".claude/skills/audit-database-support/SKILL.md"
117
+ - ".claude/skills/audit-durability/SKILL.md"
114
118
  - ".saturnci/Dockerfile"
115
119
  - ".saturnci/database.yml"
116
120
  - ".saturnci/docker-compose.yml"
117
121
  - ".saturnci/pre.sh"
118
122
  - CHANGELOG-PRO.md
119
123
  - CHANGELOG.md
124
+ - CLAUDE.md
120
125
  - LICENSE.txt
121
126
  - PRO-LICENSE.txt
122
127
  - README.md
@@ -139,17 +144,24 @@ files:
139
144
  - app/views/layouts/ductwork/application.html.erb
140
145
  - config/routes.rb
141
146
  - lib/ductwork.rb
147
+ - lib/ductwork/branch_claim.rb
142
148
  - lib/ductwork/cli.rb
143
149
  - lib/ductwork/configuration.rb
144
150
  - lib/ductwork/context.rb
151
+ - lib/ductwork/database_clock.rb
145
152
  - lib/ductwork/dsl/branch_builder.rb
146
153
  - lib/ductwork/dsl/definition_builder.rb
147
154
  - lib/ductwork/engine.rb
148
- - lib/ductwork/job_claim.rb
155
+ - lib/ductwork/execution_claim.rb
156
+ - lib/ductwork/fault_injection.rb
149
157
  - lib/ductwork/machine_identifier.rb
150
158
  - lib/ductwork/migration.rb
151
159
  - lib/ductwork/migration_helper.rb
160
+ - lib/ductwork/models/advancement.rb
161
+ - lib/ductwork/models/attempt.rb
152
162
  - lib/ductwork/models/availability.rb
163
+ - lib/ductwork/models/branch.rb
164
+ - lib/ductwork/models/branch_link.rb
153
165
  - lib/ductwork/models/execution.rb
154
166
  - lib/ductwork/models/job.rb
155
167
  - lib/ductwork/models/pipeline.rb
@@ -158,8 +170,11 @@ files:
158
170
  - lib/ductwork/models/result.rb
159
171
  - lib/ductwork/models/run.rb
160
172
  - lib/ductwork/models/step.rb
173
+ - lib/ductwork/models/transition.rb
161
174
  - lib/ductwork/models/tuple.rb
162
- - lib/ductwork/optimistic_locking_job_claim.rb
175
+ - lib/ductwork/models/workflow.rb
176
+ - lib/ductwork/optimistic_locking_execution_claim.rb
177
+ - lib/ductwork/processes/health_check.rb
163
178
  - lib/ductwork/processes/job_worker.rb
164
179
  - lib/ductwork/processes/job_worker_runner.rb
165
180
  - lib/ductwork/processes/launcher.rb
@@ -169,7 +184,8 @@ files:
169
184
  - lib/ductwork/processes/process_supervisor_runner.rb
170
185
  - lib/ductwork/processes/thread_supervisor.rb
171
186
  - lib/ductwork/processes/thread_supervisor_runner.rb
172
- - lib/ductwork/row_locking_job_claim.rb
187
+ - lib/ductwork/processes/worker_health_check.rb
188
+ - lib/ductwork/row_locking_execution_claim.rb
173
189
  - lib/ductwork/running_context.rb
174
190
  - lib/ductwork/testing.rb
175
191
  - lib/ductwork/testing/helpers.rb
@@ -180,7 +196,11 @@ files:
180
196
  - lib/generators/ductwork/install/install_generator.rb
181
197
  - lib/generators/ductwork/install/templates/bin/ductwork
182
198
  - lib/generators/ductwork/install/templates/config/ductwork.yml
199
+ - lib/generators/ductwork/install/templates/db/create_ductwork_advancements.rb
200
+ - lib/generators/ductwork/install/templates/db/create_ductwork_attempts.rb
183
201
  - lib/generators/ductwork/install/templates/db/create_ductwork_availabilities.rb
202
+ - lib/generators/ductwork/install/templates/db/create_ductwork_branch_links.rb
203
+ - lib/generators/ductwork/install/templates/db/create_ductwork_branches.rb
184
204
  - lib/generators/ductwork/install/templates/db/create_ductwork_executions.rb
185
205
  - lib/generators/ductwork/install/templates/db/create_ductwork_jobs.rb
186
206
  - lib/generators/ductwork/install/templates/db/create_ductwork_pipelines.rb
@@ -188,10 +208,31 @@ files:
188
208
  - lib/generators/ductwork/install/templates/db/create_ductwork_results.rb
189
209
  - lib/generators/ductwork/install/templates/db/create_ductwork_runs.rb
190
210
  - lib/generators/ductwork/install/templates/db/create_ductwork_steps.rb
211
+ - lib/generators/ductwork/install/templates/db/create_ductwork_transitions.rb
191
212
  - lib/generators/ductwork/install/templates/db/create_ductwork_tuples.rb
192
213
  - lib/generators/ductwork/update/USAGE
214
+ - lib/generators/ductwork/update/templates/db/add_crash_count_to_ductwork_advancements.rb
215
+ - lib/generators/ductwork/update/templates/db/add_crash_count_to_ductwork_executions.rb
216
+ - lib/generators/ductwork/update/templates/db/add_indexes_to_ductwork_results.rb
217
+ - lib/generators/ductwork/update/templates/db/add_indexes_to_ductwork_runs.rb
218
+ - lib/generators/ductwork/update/templates/db/add_indexes_to_ductwork_transitions.rb
219
+ - lib/generators/ductwork/update/templates/db/add_pipeline_started_index_to_ductwork_runs.rb
220
+ - lib/generators/ductwork/update/templates/db/add_process_id_to_ductwork_executions.rb
221
+ - lib/generators/ductwork/update/templates/db/add_role_to_ductwork_processes.rb
222
+ - lib/generators/ductwork/update/templates/db/associate_branches_to_runs.rb
223
+ - lib/generators/ductwork/update/templates/db/associate_steps_to_branches.rb
224
+ - lib/generators/ductwork/update/templates/db/associate_steps_to_runs.rb
225
+ - lib/generators/ductwork/update/templates/db/associate_tuples_to_runs.rb
226
+ - lib/generators/ductwork/update/templates/db/backfill_branch_ids_on_steps.rb
227
+ - lib/generators/ductwork/update/templates/db/create_ductwork_advancements.rb
228
+ - lib/generators/ductwork/update/templates/db/create_ductwork_branch_links.rb
229
+ - lib/generators/ductwork/update/templates/db/create_ductwork_branches.rb
230
+ - lib/generators/ductwork/update/templates/db/create_ductwork_runs.rb
231
+ - lib/generators/ductwork/update/templates/db/create_ductwork_transitions.rb
193
232
  - lib/generators/ductwork/update/templates/db/denormalize_pipeline_klass_on_availabilities.rb
194
233
  - lib/generators/ductwork/update/templates/db/migrate_tables_to_uuid_primary_key.rb
234
+ - lib/generators/ductwork/update/templates/db/rename_runs_to_attempts.rb
235
+ - lib/generators/ductwork/update/templates/db/update_process_associations.rb
195
236
  - lib/generators/ductwork/update/update_generator.rb
196
237
  homepage: https://github.com/ductwork/ductwork
197
238
  licenses:
@@ -200,7 +241,7 @@ metadata:
200
241
  homepage_uri: https://github.com/ductwork/ductwork
201
242
  changelog_uri: https://github.com/ductwork/ductwork/blob/main/CHANGELOG.md
202
243
  rubygems_mfa_required: 'true'
203
- documentation_uri: https://docs.getductwork.io/
244
+ documentation_uri: https://www.getductwork.io/docs/
204
245
  rdoc_options: []
205
246
  require_paths:
206
247
  - app
@@ -217,7 +258,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
258
  - !ruby/object:Gem::Version
218
259
  version: '0'
219
260
  requirements: []
220
- rubygems_version: 4.0.6
261
+ rubygems_version: 4.0.16
221
262
  specification_version: 4
222
263
  summary: A Ruby pipeline framework
223
264
  test_files: []
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Ductwork
4
- class OptimisticLockingJobClaim
5
- def initialize(klass)
6
- @id = nil
7
- @job = nil
8
- @klass = klass
9
- @process_id = ::Process.pid
10
- end
11
-
12
- def latest
13
- @id = latest_availability_id
14
-
15
- if id.present?
16
- rows_updated = claim_availability
17
-
18
- if rows_updated == 1
19
- Ductwork.logger.debug(
20
- msg: "Job claimed",
21
- role: :job_worker,
22
- process_id: process_id,
23
- availability_id: id
24
- )
25
-
26
- @job = find_job
27
-
28
- update_state
29
- else
30
- Ductwork.logger.debug(
31
- msg: "Did not claim job, avoided race condition",
32
- role: :job_worker,
33
- process_id: process_id,
34
- availability_id: id
35
- )
36
- end
37
- else
38
- Ductwork.logger.debug(
39
- msg: "No available job to claim",
40
- role: :job_worker,
41
- process_id: process_id,
42
- pipeline: klass
43
- )
44
- end
45
-
46
- job
47
- end
48
-
49
- private
50
-
51
- attr_reader :id, :job, :klass, :process_id
52
-
53
- def latest_availability_id
54
- Ductwork::Availability
55
- .where("ductwork_availabilities.started_at <= ?", Time.current)
56
- .where(completed_at: nil, pipeline_klass: klass)
57
- .order(:started_at)
58
- .limit(1)
59
- .pluck(:id)
60
- .first
61
- end
62
-
63
- def claim_availability
64
- Ductwork::Availability
65
- .where(id: id, completed_at: nil)
66
- .update_all(completed_at: Time.current, process_id: process_id)
67
- end
68
-
69
- def find_job
70
- Ductwork::Job
71
- .joins(executions: :availability)
72
- .find_by!(ductwork_availabilities: { id:, process_id: })
73
- end
74
-
75
- def update_state
76
- Ductwork::Record.transaction do
77
- Ductwork::Execution
78
- .joins(:availability)
79
- .where(completed_at: nil)
80
- .where(ductwork_availabilities: { id: })
81
- .sole
82
- .update!(process_id:)
83
- job.step.in_progress!
84
- job.step.pipeline.in_progress!
85
- end
86
- end
87
- end
88
- end