geneva_drive 0.7.0 → 0.9.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/MANUAL.md +299 -5
  4. data/README.md +14 -1
  5. data/Rakefile +28 -1
  6. data/bin/matrix +76 -0
  7. data/bin/md2html +114 -0
  8. data/lib/generators/geneva_drive/install/templates/add_resumable_step_support.rb +5 -9
  9. data/lib/generators/geneva_drive/install/templates/add_signals_support.rb +5 -10
  10. data/lib/generators/geneva_drive/install/templates/create_workflows_migration.rb +1 -1
  11. data/lib/generators/geneva_drive/install/templates/initializer.rb.tt +33 -2
  12. data/lib/geneva_drive/dispatchers/active_job_dispatcher.rb +33 -0
  13. data/lib/geneva_drive/dispatchers/sidekiq_dispatcher.rb +112 -0
  14. data/lib/geneva_drive/engine.rb +13 -0
  15. data/lib/geneva_drive/executor.rb +23 -3
  16. data/lib/geneva_drive/job_options.rb +7 -3
  17. data/lib/geneva_drive/jobs/perform_step_job.rb +2 -35
  18. data/lib/geneva_drive/jobs/sidekiq_housekeeping_job.rb +32 -0
  19. data/lib/geneva_drive/jobs/sidekiq_perform_step_job.rb +35 -0
  20. data/lib/geneva_drive/jobs/step_execution_lookup.rb +42 -0
  21. data/lib/geneva_drive/json_column.rb +72 -0
  22. data/lib/geneva_drive/migration_helpers.rb +60 -3
  23. data/lib/geneva_drive/removed_step_definition.rb +34 -0
  24. data/lib/geneva_drive/signal.rb +4 -2
  25. data/lib/geneva_drive/step_collection.rb +31 -7
  26. data/lib/geneva_drive/step_definition.rb +9 -0
  27. data/lib/geneva_drive/step_execution.rb +3 -2
  28. data/lib/geneva_drive/version.rb +1 -1
  29. data/lib/geneva_drive/workflow.rb +200 -39
  30. data/lib/geneva_drive.rb +65 -0
  31. data/test/dummy/config/database.yml +40 -5
  32. data/test/dummy/config/initializers/geneva_drive.rb +78 -0
  33. data/test/dummy/db/mysql/schema-8.1.rb +95 -0
  34. data/test/dummy/db/postgres/schema-8.1.rb +99 -0
  35. data/test/dummy/db/sqlite/schema-7.2.rb +96 -0
  36. data/test/dummy/db/sqlite/schema-8.0.rb +96 -0
  37. data/test/dummy/db/sqlite/schema-8.1.rb +96 -0
  38. data/test/dummy/db/sqlite/test.sqlite3 +0 -0
  39. data/test/dummy/db/sqlite/test.sqlite3-0 +0 -0
  40. data/test/dummy/db/sqlite/test.sqlite3-1 +0 -0
  41. data/test/dummy/db/sqlite/test.sqlite3-2 +0 -0
  42. data/test/dummy/db/sqlite/test.sqlite3-3 +0 -0
  43. data/test/dummy/db/sqlite/test.sqlite3-4 +0 -0
  44. data/test/dummy/db/sqlite/test.sqlite3-5 +0 -0
  45. data/test/dummy/db/sqlite/test.sqlite3-6 +0 -0
  46. data/test/dummy/db/sqlite/test.sqlite3-7 +0 -0
  47. data/test/dummy/db/sqlite/test.sqlite3-8 +0 -0
  48. data/test/dummy/db/sqlite/test.sqlite3-9 +0 -0
  49. data/test/dummy/db/sqlite/test.sqlite3_0 +0 -0
  50. data/test/dummy/db/sqlite/test.sqlite3_1 +0 -0
  51. data/test/dummy/db/sqlite/test.sqlite3_2 +0 -0
  52. data/test/dummy/db/sqlite/test.sqlite3_3 +0 -0
  53. data/test/dummy/db/sqlite/test.sqlite3_4 +0 -0
  54. data/test/dummy/db/sqlite/test.sqlite3_5 +0 -0
  55. data/test/dummy/db/sqlite/test.sqlite3_6 +0 -0
  56. data/test/dummy/db/sqlite/test.sqlite3_7 +0 -0
  57. data/test/dummy/db/sqlite/test.sqlite3_8 +0 -0
  58. data/test/dummy/db/sqlite/test.sqlite3_9 +0 -0
  59. data/test/dummy/db/sqlite3/schema-7.2.rb +96 -0
  60. data/test/dummy/db/sqlite3/schema-8.1.rb +96 -0
  61. data/test/dummy/db/sqlite3/test.sqlite3 +0 -0
  62. data/test/dummy/db/sqlite3/test.sqlite3_0 +0 -0
  63. data/test/dummy/db/sqlite3/test.sqlite3_1 +0 -0
  64. data/test/dummy/db/sqlite3/test.sqlite3_2 +0 -0
  65. data/test/dummy/db/sqlite3/test.sqlite3_3 +0 -0
  66. data/test/dummy/db/sqlite3/test.sqlite3_4 +0 -0
  67. data/test/dummy/db/sqlite3/test.sqlite3_5 +0 -0
  68. data/test/dummy/db/sqlite3/test.sqlite3_6 +0 -0
  69. data/test/dummy/db/sqlite3/test.sqlite3_7 +0 -0
  70. data/test/dummy/db/sqlite3/test.sqlite3_8 +0 -0
  71. data/test/dummy/db/sqlite3/test.sqlite3_9 +0 -0
  72. data/test/dummy_install/db/migrate/20260217112949_create_geneva_drive_workflows.rb +76 -0
  73. data/test/dummy_install/db/migrate/20260217112950_create_geneva_drive_step_executions.rb +99 -0
  74. data/test/dummy_install/db/migrate/20260217112951_add_finished_at_to_geneva_drive_step_executions.rb +27 -0
  75. data/test/dummy_install/db/migrate/20260217112952_add_error_class_name_to_geneva_drive_step_executions.rb +9 -0
  76. data/test/dummy_install/db/migrate/20260217112953_add_resumable_step_support_to_geneva_drive_step_executions.rb +128 -0
  77. data/test/dummy_install/db/migrate/20260217112954_add_chained_step_executions_to_geneva_drive_step_executions.rb +136 -0
  78. data/test/dummy_install/db/schema.rb +75 -0
  79. data/test/dummy_install/log/test.log +1852 -0
  80. data/test/generators/install_generator_test.rb +56 -0
  81. data/test/geneva_drive_test.rb +10 -0
  82. data/test/migration_helpers_test.rb +62 -0
  83. data/test/sidekiq/sidekiq_dispatcher_test.rb +322 -0
  84. data/test/sidekiq/sidekiq_redis_test.rb +115 -0
  85. data/test/test_helper.rb +51 -13
  86. data/test/workflow/pause_resume_test.rb +15 -0
  87. data/test/workflow/removed_step_test.rb +294 -0
  88. data/test/workflow/resume_at_test.rb +170 -0
  89. metadata +62 -1
@@ -0,0 +1,294 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class RemovedStepTest < ActiveSupport::TestCase
6
+ include GenevaDrive::TestHelpers
7
+
8
+ # The shape a workflow has after `capture_payment` was taken out of the
9
+ # middle of it and a gravestone left behind.
10
+ class PaymentWorkflow < GenevaDrive::Workflow
11
+ step :authorize do
12
+ Thread.current[:ran] << :authorize
13
+ end
14
+
15
+ removed_step :capture_payment
16
+
17
+ step :send_receipt do
18
+ Thread.current[:ran] << :send_receipt
19
+ end
20
+ end
21
+
22
+ # A gravestone in first position, so nothing runnable precedes it.
23
+ class LeadingRemovalWorkflow < GenevaDrive::Workflow
24
+ removed_step :old_preflight
25
+
26
+ step :only_step do
27
+ Thread.current[:ran] << :only_step
28
+ end
29
+ end
30
+
31
+ # A gravestone in last position, so nothing runnable follows it.
32
+ class TrailingRemovalWorkflow < GenevaDrive::Workflow
33
+ step :only_step do
34
+ Thread.current[:ran] << :only_step
35
+ end
36
+
37
+ removed_step :old_teardown
38
+ end
39
+
40
+ # Every step removed - there is nothing left to run at all.
41
+ class FullyRemovedWorkflow < GenevaDrive::Workflow
42
+ removed_step :gone_one
43
+ removed_step :gone_two
44
+ end
45
+
46
+ # A step deleted outright, with no gravestone. This is the situation
47
+ # removed_step exists to prevent, kept here to prove the default is
48
+ # unchanged: the workflow still pauses rather than guessing.
49
+ class UndeclaredRemovalWorkflow < GenevaDrive::Workflow
50
+ step :step_one do
51
+ Thread.current[:ran] << :step_one
52
+ end
53
+
54
+ step :step_two do
55
+ Thread.current[:ran] << :step_two
56
+ end
57
+ end
58
+
59
+ setup do
60
+ @user = create_user
61
+ Thread.current[:ran] = []
62
+ end
63
+
64
+ teardown do
65
+ Thread.current[:ran] = nil
66
+ end
67
+
68
+ # ===========================================
69
+ # The declaration itself
70
+ # ===========================================
71
+
72
+ test "removed_step registers a gravestone that reports itself as removed" do
73
+ step_def = PaymentWorkflow.steps.named("capture_payment")
74
+
75
+ assert_not_nil step_def
76
+ assert_predicate step_def, :removed?
77
+ assert_equal "capture_payment", step_def.name
78
+ end
79
+
80
+ test "an ordinary step is not removed" do
81
+ assert_not_predicate PaymentWorkflow.steps.named("authorize"), :removed?
82
+ end
83
+
84
+ test "a removed step keeps its name resolvable" do
85
+ assert PaymentWorkflow.steps.key?("capture_payment")
86
+ end
87
+
88
+ test "a removed step holds its position in the declared order" do
89
+ assert_equal %w[authorize capture_payment send_receipt], PaymentWorkflow.steps.map(&:name)
90
+ end
91
+
92
+ test "runnable omits removed steps and removed lists them" do
93
+ assert_equal %w[authorize send_receipt], PaymentWorkflow.steps.runnable.map(&:name)
94
+ assert_equal %w[capture_payment], PaymentWorkflow.steps.removed.map(&:name)
95
+ end
96
+
97
+ test "removed_step refuses a name already taken by a step" do
98
+ error = assert_raises(GenevaDrive::StepConfigurationError) do
99
+ Class.new(GenevaDrive::Workflow) do
100
+ def self.name = "DoubleDeclarationWorkflow"
101
+
102
+ step :thing do
103
+ # no-op
104
+ end
105
+
106
+ removed_step :thing
107
+ end
108
+ end
109
+
110
+ assert_match(/already defined/, error.message)
111
+ end
112
+
113
+ test "removed_step requires a name" do
114
+ assert_raises(ArgumentError) do
115
+ Class.new(GenevaDrive::Workflow) do
116
+ removed_step nil
117
+ end
118
+ end
119
+ end
120
+
121
+ test "before_step can still reference a removed step" do
122
+ klass = Class.new(GenevaDrive::Workflow) do
123
+ def self.name = "PositionedAroundRemovalWorkflow"
124
+
125
+ removed_step :gone
126
+
127
+ step :inserted, before_step: :gone do
128
+ # no-op
129
+ end
130
+ end
131
+
132
+ assert_equal %w[inserted gone], klass.steps.map(&:name)
133
+ end
134
+
135
+ # ===========================================
136
+ # Navigation never lands on a gravestone
137
+ # ===========================================
138
+
139
+ test "next_after steps over a removed step" do
140
+ assert_equal "send_receipt", PaymentWorkflow.steps.next_after("authorize").name
141
+ end
142
+
143
+ test "next_after from a removed step returns the next runnable one" do
144
+ assert_equal "send_receipt", PaymentWorkflow.steps.next_after("capture_payment").name
145
+ end
146
+
147
+ test "next_after returns nil when only removed steps remain" do
148
+ assert_nil TrailingRemovalWorkflow.steps.next_after("only_step")
149
+ end
150
+
151
+ test "next_after from the beginning skips a leading removed step" do
152
+ assert_equal "only_step", LeadingRemovalWorkflow.steps.next_after(nil).name
153
+ end
154
+
155
+ test "next_after still returns nil for a name the collection never had" do
156
+ assert_nil PaymentWorkflow.steps.next_after("never_existed")
157
+ end
158
+
159
+ test "previous_before steps over a removed step" do
160
+ assert_equal "authorize", PaymentWorkflow.steps.previous_before("send_receipt").name
161
+ end
162
+
163
+ test "previous_before returns nil when only removed steps precede" do
164
+ assert_nil LeadingRemovalWorkflow.steps.previous_before("only_step")
165
+ end
166
+
167
+ # ===========================================
168
+ # Scheduling never spools a removed step
169
+ # ===========================================
170
+
171
+ test "a new workflow runs straight past a removed middle step" do
172
+ workflow = PaymentWorkflow.create!(hero: @user)
173
+ speedrun_workflow(workflow)
174
+
175
+ assert_equal %i[authorize send_receipt], Thread.current[:ran]
176
+ assert_workflow_state(workflow, :finished)
177
+ assert_empty workflow.step_executions.where(step_name: "capture_payment")
178
+ end
179
+
180
+ test "a new workflow starts at the first runnable step, not a leading gravestone" do
181
+ workflow = LeadingRemovalWorkflow.create!(hero: @user)
182
+
183
+ assert_equal "only_step", workflow.next_step_name
184
+
185
+ speedrun_workflow(workflow)
186
+
187
+ assert_equal %i[only_step], Thread.current[:ran]
188
+ assert_workflow_state(workflow, :finished)
189
+ end
190
+
191
+ test "a trailing gravestone finishes the workflow instead of being scheduled" do
192
+ workflow = TrailingRemovalWorkflow.create!(hero: @user)
193
+ speedrun_workflow(workflow)
194
+
195
+ assert_workflow_state(workflow, :finished)
196
+ assert_empty workflow.step_executions.where(step_name: "old_teardown")
197
+ end
198
+
199
+ test "a workflow whose every step was removed finishes immediately" do
200
+ workflow = FullyRemovedWorkflow.create!(hero: @user)
201
+
202
+ assert_workflow_state(workflow, :finished)
203
+ assert_empty workflow.step_executions
204
+ end
205
+
206
+ # ===========================================
207
+ # Executions scheduled before the removal shipped
208
+ # ===========================================
209
+
210
+ test "an execution scheduled before the removal is skipped and the workflow continues" do
211
+ workflow = PaymentWorkflow.create!(hero: @user)
212
+
213
+ # Stand in for a rolling deploy: this row was written by the old code,
214
+ # which still had capture_payment as a real step.
215
+ execution = reschedule_at(workflow, "capture_payment")
216
+
217
+ execution.execute!
218
+
219
+ assert_equal "skipped", execution.reload.state
220
+ assert_equal "skipped", execution.outcome
221
+
222
+ speedrun_workflow(workflow)
223
+
224
+ assert_equal %i[send_receipt], Thread.current[:ran]
225
+ assert_workflow_state(workflow, :finished)
226
+ end
227
+
228
+ test "an execution for a trailing removed step finishes the workflow" do
229
+ workflow = TrailingRemovalWorkflow.create!(hero: @user)
230
+ execution = reschedule_at(workflow, "old_teardown")
231
+
232
+ execution.execute!
233
+
234
+ assert_equal "skipped", execution.reload.state
235
+ assert_workflow_state(workflow, :finished)
236
+ end
237
+
238
+ test "a step deleted without a gravestone still pauses the workflow" do
239
+ workflow = UndeclaredRemovalWorkflow.create!(hero: @user)
240
+ execution = reschedule_at(workflow, "deleted_without_a_trace")
241
+
242
+ assert_raises(GenevaDrive::StepNotDefinedError) { execution.execute! }
243
+
244
+ assert_workflow_state(workflow, :paused)
245
+ end
246
+
247
+ # ===========================================
248
+ # Knowing when the gravestone can go
249
+ # ===========================================
250
+
251
+ test "removed_steps_in_flight counts rows still pointing at a removed step" do
252
+ workflow = PaymentWorkflow.create!(hero: @user)
253
+ reschedule_at(workflow, "capture_payment")
254
+
255
+ assert_equal({"capture_payment" => 1}, PaymentWorkflow.removed_steps_in_flight)
256
+ end
257
+
258
+ test "removed_steps_in_flight ignores workflows that will never run again" do
259
+ workflow = PaymentWorkflow.create!(hero: @user)
260
+ reschedule_at(workflow, "capture_payment")
261
+ workflow.update!(state: "canceled")
262
+
263
+ assert_empty PaymentWorkflow.removed_steps_in_flight
264
+ end
265
+
266
+ test "removed_steps_in_flight is empty once nothing references the name" do
267
+ PaymentWorkflow.create!(hero: @user)
268
+
269
+ assert_empty PaymentWorkflow.removed_steps_in_flight
270
+ end
271
+
272
+ test "removed_steps_in_flight is empty for a workflow with no removals" do
273
+ assert_empty UndeclaredRemovalWorkflow.removed_steps_in_flight
274
+ end
275
+
276
+ private
277
+
278
+ # Replaces whatever is scheduled with an execution for the given step name,
279
+ # the way a row written by a previous deploy would look.
280
+ def reschedule_at(workflow, step_name)
281
+ workflow.step_executions.where(state: %w[scheduled waiting]).update_all(
282
+ state: "canceled",
283
+ outcome: "canceled",
284
+ canceled_at: Time.current
285
+ )
286
+ execution = workflow.step_executions.create!(
287
+ step_name: step_name,
288
+ state: "scheduled",
289
+ scheduled_for: Time.current
290
+ )
291
+ workflow.update!(next_step_name: step_name, current_step_name: nil)
292
+ execution
293
+ end
294
+ end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class ResumeAtTest < ActiveSupport::TestCase
6
+ include GenevaDrive::TestHelpers
7
+
8
+ class ThreeStepWorkflow < GenevaDrive::Workflow
9
+ step :step_one do
10
+ Thread.current[:ran] << :step_one
11
+ end
12
+
13
+ step :step_two do
14
+ Thread.current[:ran] << :step_two
15
+ end
16
+
17
+ step :step_three do
18
+ Thread.current[:ran] << :step_three
19
+ end
20
+ end
21
+
22
+ class WorkflowWithRemoval < GenevaDrive::Workflow
23
+ step :step_one do
24
+ Thread.current[:ran] << :step_one
25
+ end
26
+
27
+ removed_step :parked_forever
28
+
29
+ step :step_three do
30
+ Thread.current[:ran] << :step_three
31
+ end
32
+ end
33
+
34
+ setup do
35
+ @user = create_user
36
+ Thread.current[:ran] = []
37
+ end
38
+
39
+ teardown do
40
+ Thread.current[:ran] = nil
41
+ end
42
+
43
+ # ===========================================
44
+ # resume_at!
45
+ # ===========================================
46
+
47
+ test "resume_at! continues from the named step" do
48
+ workflow = paused_at(ThreeStepWorkflow.create!(hero: @user), "step_two")
49
+
50
+ execution = workflow.resume_at!(:step_three)
51
+
52
+ assert_equal "step_three", execution.step_name
53
+ assert_equal "step_three", workflow.reload.next_step_name
54
+ assert_equal "ready", workflow.state
55
+
56
+ speedrun_workflow(workflow)
57
+
58
+ assert_equal %i[step_three], Thread.current[:ran]
59
+ assert_workflow_state(workflow, :finished)
60
+ end
61
+
62
+ test "resume_at! cancels the execution the workflow was pointed at" do
63
+ workflow = ThreeStepWorkflow.create!(hero: @user)
64
+ stale = workflow.current_execution
65
+ workflow.pause!
66
+
67
+ workflow.resume_at!(:step_three)
68
+
69
+ assert_equal "canceled", stale.reload.state
70
+ end
71
+
72
+ test "resume_at! accepts a string as readily as a symbol" do
73
+ workflow = paused_at(ThreeStepWorkflow.create!(hero: @user), "step_two")
74
+
75
+ assert_equal "step_three", workflow.resume_at!("step_three").step_name
76
+ end
77
+
78
+ test "resume_at! rejects a step that is not defined" do
79
+ workflow = paused_at(ThreeStepWorkflow.create!(hero: @user), "step_two")
80
+
81
+ error = assert_raises(GenevaDrive::StepNotDefinedError) { workflow.resume_at!(:nowhere) }
82
+
83
+ assert_match(/not defined/, error.message)
84
+ assert_match(/step_one, step_two, step_three/, error.message)
85
+ assert_equal "paused", workflow.reload.state
86
+ end
87
+
88
+ test "resume_at! refuses to land on a removed step" do
89
+ workflow = paused_at(WorkflowWithRemoval.create!(hero: @user), "step_one")
90
+
91
+ error = assert_raises(GenevaDrive::StepNotDefinedError) { workflow.resume_at!(:parked_forever) }
92
+
93
+ assert_match(/removed_step/, error.message)
94
+ assert_equal "paused", workflow.reload.state
95
+ end
96
+
97
+ test "resume_at! only applies to paused workflows" do
98
+ workflow = ThreeStepWorkflow.create!(hero: @user)
99
+
100
+ assert_raises(GenevaDrive::InvalidStateError) { workflow.resume_at!(:step_three) }
101
+ end
102
+
103
+ # ===========================================
104
+ # resume! on a workflow pointed at a vanished step
105
+ # ===========================================
106
+
107
+ test "resume! explains itself when the step it points at is gone" do
108
+ workflow = paused_at(ThreeStepWorkflow.create!(hero: @user), "deleted_without_a_trace")
109
+
110
+ error = assert_raises(GenevaDrive::StepNotDefinedError) { workflow.resume! }
111
+
112
+ assert_match(/no longer defined/, error.message)
113
+ assert_match(/resume_at!/, error.message)
114
+ assert_match(/removed_step :deleted_without_a_trace/, error.message)
115
+ assert_match(/step_one, step_two, step_three/, error.message)
116
+ end
117
+
118
+ test "resume_at! rescues a workflow stranded by a vanished step" do
119
+ workflow = paused_at(ThreeStepWorkflow.create!(hero: @user), "deleted_without_a_trace")
120
+
121
+ workflow.resume_at!(:step_three)
122
+ speedrun_workflow(workflow)
123
+
124
+ assert_equal %i[step_three], Thread.current[:ran]
125
+ assert_workflow_state(workflow, :finished)
126
+ end
127
+
128
+ # ===========================================
129
+ # A step removed while an execution was parked
130
+ # ===========================================
131
+
132
+ test "resume! releases an execution parked on a since-removed step" do
133
+ workflow = WorkflowWithRemoval.create!(hero: @user)
134
+
135
+ # The old code parked here waiting for a signal; the new code has only a
136
+ # gravestone, so nothing can ever match.
137
+ workflow.step_executions.where(state: %w[scheduled waiting]).update_all(
138
+ state: "canceled", outcome: "canceled", canceled_at: Time.current
139
+ )
140
+ parked = workflow.step_executions.create!(
141
+ step_name: "parked_forever",
142
+ state: "waiting",
143
+ scheduled_for: Time.current,
144
+ waiting_since: Time.current
145
+ )
146
+ workflow.update!(next_step_name: "parked_forever", current_step_name: nil)
147
+ workflow.pause!
148
+
149
+ workflow.resume!
150
+
151
+ assert_equal "skipped", parked.reload.state
152
+
153
+ speedrun_workflow(workflow)
154
+
155
+ assert_equal %i[step_three], Thread.current[:ran]
156
+ assert_workflow_state(workflow, :finished)
157
+ end
158
+
159
+ private
160
+
161
+ # Puts the workflow in the state it would be in after pausing while pointed
162
+ # at the given step name, with no live execution left behind.
163
+ def paused_at(workflow, step_name)
164
+ workflow.step_executions.where(state: %w[scheduled waiting]).update_all(
165
+ state: "canceled", outcome: "canceled", canceled_at: Time.current
166
+ )
167
+ workflow.update!(state: "paused", next_step_name: step_name, current_step_name: nil)
168
+ workflow
169
+ end
170
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geneva_drive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
@@ -94,6 +94,7 @@ files:
94
94
  - MANUAL.md
95
95
  - README.md
96
96
  - Rakefile
97
+ - bin/matrix
97
98
  - bin/md2html
98
99
  - bin/rails
99
100
  - bin/rubocop
@@ -113,6 +114,8 @@ files:
113
114
  - lib/generators/geneva_drive/install/templates/initializer.rb.tt
114
115
  - lib/geneva_drive.rb
115
116
  - lib/geneva_drive/combined_exception_policy.rb
117
+ - lib/geneva_drive/dispatchers/active_job_dispatcher.rb
118
+ - lib/geneva_drive/dispatchers/sidekiq_dispatcher.rb
116
119
  - lib/geneva_drive/engine.rb
117
120
  - lib/geneva_drive/exception_policy.rb
118
121
  - lib/geneva_drive/executor.rb
@@ -121,7 +124,12 @@ files:
121
124
  - lib/geneva_drive/job_options.rb
122
125
  - lib/geneva_drive/jobs/housekeeping_job.rb
123
126
  - lib/geneva_drive/jobs/perform_step_job.rb
127
+ - lib/geneva_drive/jobs/sidekiq_housekeeping_job.rb
128
+ - lib/geneva_drive/jobs/sidekiq_perform_step_job.rb
129
+ - lib/geneva_drive/jobs/step_execution_lookup.rb
130
+ - lib/geneva_drive/json_column.rb
124
131
  - lib/geneva_drive/migration_helpers.rb
132
+ - lib/geneva_drive/removed_step_definition.rb
125
133
  - lib/geneva_drive/resumable_step_definition.rb
126
134
  - lib/geneva_drive/signal.rb
127
135
  - lib/geneva_drive/signal_matcher.rb
@@ -168,12 +176,52 @@ files:
168
176
  - test/dummy/config/initializers/assets.rb
169
177
  - test/dummy/config/initializers/content_security_policy.rb
170
178
  - test/dummy/config/initializers/filter_parameter_logging.rb
179
+ - test/dummy/config/initializers/geneva_drive.rb
171
180
  - test/dummy/config/initializers/inflections.rb
172
181
  - test/dummy/config/locales/en.yml
173
182
  - test/dummy/config/puma.rb
174
183
  - test/dummy/config/routes.rb
175
184
  - test/dummy/config/storage.yml
176
185
  - test/dummy/db/migrate/20241217000000_create_users.rb
186
+ - test/dummy/db/mysql/schema-8.1.rb
187
+ - test/dummy/db/postgres/schema-8.1.rb
188
+ - test/dummy/db/sqlite/schema-7.2.rb
189
+ - test/dummy/db/sqlite/schema-8.0.rb
190
+ - test/dummy/db/sqlite/schema-8.1.rb
191
+ - test/dummy/db/sqlite/test.sqlite3
192
+ - test/dummy/db/sqlite/test.sqlite3-0
193
+ - test/dummy/db/sqlite/test.sqlite3-1
194
+ - test/dummy/db/sqlite/test.sqlite3-2
195
+ - test/dummy/db/sqlite/test.sqlite3-3
196
+ - test/dummy/db/sqlite/test.sqlite3-4
197
+ - test/dummy/db/sqlite/test.sqlite3-5
198
+ - test/dummy/db/sqlite/test.sqlite3-6
199
+ - test/dummy/db/sqlite/test.sqlite3-7
200
+ - test/dummy/db/sqlite/test.sqlite3-8
201
+ - test/dummy/db/sqlite/test.sqlite3-9
202
+ - test/dummy/db/sqlite/test.sqlite3_0
203
+ - test/dummy/db/sqlite/test.sqlite3_1
204
+ - test/dummy/db/sqlite/test.sqlite3_2
205
+ - test/dummy/db/sqlite/test.sqlite3_3
206
+ - test/dummy/db/sqlite/test.sqlite3_4
207
+ - test/dummy/db/sqlite/test.sqlite3_5
208
+ - test/dummy/db/sqlite/test.sqlite3_6
209
+ - test/dummy/db/sqlite/test.sqlite3_7
210
+ - test/dummy/db/sqlite/test.sqlite3_8
211
+ - test/dummy/db/sqlite/test.sqlite3_9
212
+ - test/dummy/db/sqlite3/schema-7.2.rb
213
+ - test/dummy/db/sqlite3/schema-8.1.rb
214
+ - test/dummy/db/sqlite3/test.sqlite3
215
+ - test/dummy/db/sqlite3/test.sqlite3_0
216
+ - test/dummy/db/sqlite3/test.sqlite3_1
217
+ - test/dummy/db/sqlite3/test.sqlite3_2
218
+ - test/dummy/db/sqlite3/test.sqlite3_3
219
+ - test/dummy/db/sqlite3/test.sqlite3_4
220
+ - test/dummy/db/sqlite3/test.sqlite3_5
221
+ - test/dummy/db/sqlite3/test.sqlite3_6
222
+ - test/dummy/db/sqlite3/test.sqlite3_7
223
+ - test/dummy/db/sqlite3/test.sqlite3_8
224
+ - test/dummy/db/sqlite3/test.sqlite3_9
177
225
  - test/dummy/public/400.html
178
226
  - test/dummy/public/404.html
179
227
  - test/dummy/public/406-unsupported-browser.html
@@ -182,12 +230,23 @@ files:
182
230
  - test/dummy/public/icon.png
183
231
  - test/dummy/public/icon.svg
184
232
  - test/dummy_install/config/storage.yml
233
+ - test/dummy_install/db/migrate/20260217112949_create_geneva_drive_workflows.rb
234
+ - test/dummy_install/db/migrate/20260217112950_create_geneva_drive_step_executions.rb
235
+ - test/dummy_install/db/migrate/20260217112951_add_finished_at_to_geneva_drive_step_executions.rb
236
+ - test/dummy_install/db/migrate/20260217112952_add_error_class_name_to_geneva_drive_step_executions.rb
237
+ - test/dummy_install/db/migrate/20260217112953_add_resumable_step_support_to_geneva_drive_step_executions.rb
238
+ - test/dummy_install/db/migrate/20260217112954_add_chained_step_executions_to_geneva_drive_step_executions.rb
239
+ - test/dummy_install/db/schema.rb
240
+ - test/dummy_install/log/test.log
241
+ - test/generators/install_generator_test.rb
185
242
  - test/geneva_drive_test.rb
186
243
  - test/jobs/housekeeping_job_test.rb
187
244
  - test/jobs/housekeeping_signals_test.rb
188
245
  - test/jobs/perform_step_job_double_deferral_test.rb
189
246
  - test/jobs/perform_step_job_test.rb
190
247
  - test/migration_helpers_test.rb
248
+ - test/sidekiq/sidekiq_dispatcher_test.rb
249
+ - test/sidekiq/sidekiq_redis_test.rb
191
250
  - test/step_execution/metadata_accessor_test.rb
192
251
  - test/test_helper.rb
193
252
  - test/test_helper_test.rb
@@ -205,10 +264,12 @@ files:
205
264
  - test/workflow/pause_resume_test.rb
206
265
  - test/workflow/precondition_exception_test.rb
207
266
  - test/workflow/reattempt_on_exception_integration_test.rb
267
+ - test/workflow/removed_step_test.rb
208
268
  - test/workflow/resumable_step_integration_test.rb
209
269
  - test/workflow/resumable_step_test.rb
210
270
  - test/workflow/resumable_without_migration_test.rb
211
271
  - test/workflow/resume_and_skip_test.rb
272
+ - test/workflow/resume_at_test.rb
212
273
  - test/workflow/signal_consumption_test.rb
213
274
  - test/workflow/signal_delivery_test.rb
214
275
  - test/workflow/signal_durability_test.rb