async-graph 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +31 -2
- data/.github/workflows/docs.yml +36 -0
- data/.github/workflows/release.yml +20 -3
- data/.gitignore +15 -0
- data/README.erb +26 -1
- data/README.md +26 -1
- data/examples/all_in_one_runner.rb +48 -0
- data/examples/app_graph.rb +2 -0
- data/examples/execute_jobs.rb +12 -12
- data/examples/graph_run.rb +29 -165
- data/examples/reset.rb +10 -18
- data/examples/run.sh +4 -1
- data/lib/async-graph/graph.rb +160 -25
- data/lib/async-graph/graph_validation.rb +83 -0
- data/lib/async-graph/runner.rb +255 -0
- data/lib/async-graph/version.rb +1 -1
- data/lib/async-graph.rb +1 -0
- data/spec/async_graph_spec.rb +152 -0
- metadata +5 -1
data/spec/async_graph_spec.rb
CHANGED
|
@@ -91,4 +91,156 @@ RSpec.describe AsyncGraph::Graph do
|
|
|
91
91
|
expect(step.destinations.map(&:to)).to eq([:done])
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
|
+
|
|
95
|
+
it "validates that an entry point exists before execution" do
|
|
96
|
+
graph = described_class.new do
|
|
97
|
+
node :start do
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
expect do
|
|
102
|
+
graph.step(state: {}, node: :start)
|
|
103
|
+
end.to raise_error(AsyncGraph::ValidationError, /Entry point is not set/)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "validates graph edges before execution" do
|
|
107
|
+
graph = described_class.new do
|
|
108
|
+
node :start do
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
set_entry_point :start
|
|
112
|
+
edge :start, :missing
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
expect do
|
|
116
|
+
graph.step(state: {}, node: graph.entry)
|
|
117
|
+
end.to raise_error(AsyncGraph::ValidationError, /Edge target missing is not defined/)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "rejects duplicate node definitions" do
|
|
121
|
+
expect do
|
|
122
|
+
described_class.new do
|
|
123
|
+
node :start do
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
node :start do
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end.to raise_error(AsyncGraph::ValidationError, /Node start is already defined/)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "parks and releases join tokens inside the library" do
|
|
133
|
+
graph = described_class.new do
|
|
134
|
+
node :left do
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
node :right do
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
node :merge do
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
set_entry_point :left
|
|
144
|
+
edge %i[left right], :merge
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
parked = graph.process_join(
|
|
148
|
+
token: {
|
|
149
|
+
token_uid: "t1.left",
|
|
150
|
+
node: :merge,
|
|
151
|
+
state: {user_id: 7, left_ready: true},
|
|
152
|
+
fork_uid: "fork-1",
|
|
153
|
+
branch: :left,
|
|
154
|
+
source_node: :left,
|
|
155
|
+
awaits: {}
|
|
156
|
+
},
|
|
157
|
+
joins: {}
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
expect(parked).to be_a(AsyncGraph::JoinParked)
|
|
161
|
+
expect(parked.joins.keys).to eq([:'fork-1:merge'])
|
|
162
|
+
|
|
163
|
+
released = graph.process_join(
|
|
164
|
+
token: {
|
|
165
|
+
token_uid: "t1.right",
|
|
166
|
+
node: :merge,
|
|
167
|
+
state: {user_id: 7, right_ready: true},
|
|
168
|
+
fork_uid: "fork-1",
|
|
169
|
+
branch: :right,
|
|
170
|
+
source_node: :right,
|
|
171
|
+
awaits: {}
|
|
172
|
+
},
|
|
173
|
+
joins: parked.joins
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
aggregate_failures do
|
|
177
|
+
expect(released).to be_a(AsyncGraph::JoinReleased)
|
|
178
|
+
expect(released.joins).to eq({})
|
|
179
|
+
expect(released.token.fetch(:token_uid)).to eq("fork-1.join")
|
|
180
|
+
expect(released.token.fetch(:node)).to eq(:merge)
|
|
181
|
+
expect(released.token.fetch(:state)).to eq(
|
|
182
|
+
user_id: 7,
|
|
183
|
+
left_ready: true,
|
|
184
|
+
right_ready: true
|
|
185
|
+
)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "raises when join branches disagree on the same state key" do
|
|
190
|
+
graph = described_class.new do
|
|
191
|
+
node :left do
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
node :right do
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
node :merge do
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
set_entry_point :left
|
|
201
|
+
edge %i[left right], :merge
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
parked = graph.process_join(
|
|
205
|
+
token: {
|
|
206
|
+
token_uid: "t1.left",
|
|
207
|
+
node: :merge,
|
|
208
|
+
state: {shared: 1},
|
|
209
|
+
fork_uid: "fork-1",
|
|
210
|
+
branch: :left,
|
|
211
|
+
source_node: :left,
|
|
212
|
+
awaits: {}
|
|
213
|
+
},
|
|
214
|
+
joins: {}
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
expect do
|
|
218
|
+
graph.process_join(
|
|
219
|
+
token: {
|
|
220
|
+
token_uid: "t1.right",
|
|
221
|
+
node: :merge,
|
|
222
|
+
state: {shared: 2},
|
|
223
|
+
fork_uid: "fork-1",
|
|
224
|
+
branch: :right,
|
|
225
|
+
source_node: :right,
|
|
226
|
+
awaits: {}
|
|
227
|
+
},
|
|
228
|
+
joins: parked.joins
|
|
229
|
+
)
|
|
230
|
+
end.to raise_error(AsyncGraph::JoinConflictError, /shared/)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "validates explicit goto targets when commands are applied" do
|
|
234
|
+
graph = described_class.new do
|
|
235
|
+
node :start do
|
|
236
|
+
AsyncGraph::Command.goto(:missing)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
set_entry_point :start
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
expect do
|
|
243
|
+
graph.step(state: {}, node: graph.entry)
|
|
244
|
+
end.to raise_error(AsyncGraph::ValidationError, /Goto target missing is not defined/)
|
|
245
|
+
end
|
|
94
246
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: async-graph
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Artem Borodkin
|
|
@@ -102,6 +102,7 @@ extensions: []
|
|
|
102
102
|
extra_rdoc_files: []
|
|
103
103
|
files:
|
|
104
104
|
- ".github/workflows/ci.yml"
|
|
105
|
+
- ".github/workflows/docs.yml"
|
|
105
106
|
- ".github/workflows/release.yml"
|
|
106
107
|
- ".gitignore"
|
|
107
108
|
- ".rspec"
|
|
@@ -113,6 +114,7 @@ files:
|
|
|
113
114
|
- Rakefile
|
|
114
115
|
- async-graph.gemspec
|
|
115
116
|
- bin/console
|
|
117
|
+
- examples/all_in_one_runner.rb
|
|
116
118
|
- examples/app_graph.rb
|
|
117
119
|
- examples/execute_jobs.rb
|
|
118
120
|
- examples/graph_run.rb
|
|
@@ -120,6 +122,8 @@ files:
|
|
|
120
122
|
- examples/run.sh
|
|
121
123
|
- lib/async-graph.rb
|
|
122
124
|
- lib/async-graph/graph.rb
|
|
125
|
+
- lib/async-graph/graph_validation.rb
|
|
126
|
+
- lib/async-graph/runner.rb
|
|
123
127
|
- lib/async-graph/version.rb
|
|
124
128
|
- spec/async_graph_spec.rb
|
|
125
129
|
- spec/spec_helper.rb
|