workflow_rb 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/.gitignore +1 -1
- data/README.md +128 -125
- data/lib/workflow_rb/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cad4fe51a2b9a5d596418840c27400df4da2e0d8
|
4
|
+
data.tar.gz: 6b9803669daf8bb48231d2769b7e3a359d537d28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b08c328a31421b6fa0ad8bb7db5255b63a674fb3bddc278985ce659a348191f9fd6a0b70ed401df94e5388019e1c6a54bf17ab7f5232d80ccf52d3877472dd2
|
7
|
+
data.tar.gz: c5b62ff87e2671574c86219ac4cc1f0cb7ece19e0c8924cf26ff36ee21c98e53fa8c7443a3fb302f70fb4265605a38dc13a9f5c8848190a3c216aabf64383185
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -81,67 +81,72 @@ Each running workflow is persisted to the chosen persistence provider between ea
|
|
81
81
|
|
82
82
|
The first time a particular step within the workflow is called, the persistence_data property on the context object is *nil*. The *ExecutionResult* produced by the *run* method can either cause the workflow to proceed to the next step by providing an outcome value, instruct the workflow to sleep for a defined period or simply not move the workflow forward. If no outcome value is produced, then the step becomes re-entrant by setting persistence_data, so the workflow host will call this step again in the future buy will populate the persistence_data with it's previous value.
|
83
83
|
|
84
|
-
For example, this step will initially run with *nil* persistence_data and put the workflow to sleep for
|
85
|
-
|
86
|
-
```
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
}
|
84
|
+
For example, this step will initially run with *nil* persistence_data and put the workflow to sleep for 1 hour, while setting the persistence_data to *'something'*. 1 hour later, the step will be called again but context.persistence_data will now contain the object constructed in the previous iteration, and will now produce an outcome value of *nil*, causing the workflow to move forward.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
class MySleepStep < WorkflowRb::StepBody
|
88
|
+
def run(context)
|
89
|
+
if context.persistence_data
|
90
|
+
WorkflowRb::ExecutionResult.NextStep
|
91
|
+
else
|
92
|
+
WorkflowRb::ExecutionResult.Sleep(Time.now + 3600, 'something')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
97
96
|
```
|
98
97
|
|
99
98
|
### Passing data between steps
|
100
99
|
|
101
|
-
Each step is
|
102
|
-
|
103
|
-
The following sample shows how to define inputs and outputs on a step, it then shows how define a workflow with a typed class for internal data and how to map the inputs and outputs to
|
104
|
-
|
105
|
-
```
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
}
|
100
|
+
Each step is intended to be a black-box, therefore they support inputs and outputs. These inputs and outputs can be mapped to a data class that defines the custom data relevant to each workflow instance.
|
101
|
+
|
102
|
+
The following sample shows how to define inputs and outputs on a step, it then shows how define a workflow with a typed class for internal data and how to map the inputs and outputs to attributes on the custom data class.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
# Define some steps
|
106
|
+
class AddNumbers < WorkflowRb::StepBody
|
107
|
+
attr_accessor :input1
|
108
|
+
attr_accessor :input2
|
109
|
+
attr_accessor :answer
|
110
|
+
|
111
|
+
def run(context)
|
112
|
+
@answer = @input1 + @input2
|
113
|
+
WorkflowRb::ExecutionResult.NextStep
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class CustomMessage < WorkflowRb::StepBody
|
118
|
+
attr_accessor :message
|
119
|
+
|
120
|
+
def run(context)
|
121
|
+
puts @message
|
122
|
+
WorkflowRb::ExecutionResult.NextStep
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Define a class to hold workflow data
|
127
|
+
class MyData
|
128
|
+
attr_accessor :value1
|
129
|
+
attr_accessor :value2
|
130
|
+
attr_accessor :value3
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Define a workflow to put the steps together
|
135
|
+
class DataSample_Workflow
|
136
|
+
ID = 'data-sample'
|
137
|
+
VERSION = 1
|
138
|
+
DATA_CLASS = MyData
|
139
|
+
|
140
|
+
def build(builder)
|
141
|
+
builder
|
142
|
+
.start_with(AddNumbers)
|
143
|
+
.input(:input1) {|data| data.value1}
|
144
|
+
.input(:input2) {|data| data.value2}
|
145
|
+
.output(:value3) {|step| step.answer}
|
146
|
+
.then(CustomMessage)
|
147
|
+
.input(:message) {|data| "The answer is #{data.value3}"}
|
148
|
+
end
|
149
|
+
end
|
145
150
|
|
146
151
|
```
|
147
152
|
|
@@ -149,79 +154,80 @@ public class PassingDataWorkflow : IWorkflow<MyDataClass>
|
|
149
154
|
|
150
155
|
A workflow can take a different path depending on the outcomes of preceeding steps. The following example shows a process where first a random number of 0 or 1 is generated and is the outcome of the first step. Then, depending on the outcome value, the workflow will either fork to (TaskA + TaskB) or (TaskC + TaskD)
|
151
156
|
|
152
|
-
```
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
157
|
+
```ruby
|
158
|
+
class RandomStep < WorkflowRb::StepBody
|
159
|
+
def run(context)
|
160
|
+
WorkflowRb::ExecutionResult.Outcome(rand(2))
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class ForkSample_Workflow
|
165
|
+
ID = 'fork-sample'
|
166
|
+
VERSION = 1
|
167
|
+
DATA_CLASS = nil
|
168
|
+
|
169
|
+
def build(builder)
|
170
|
+
step1 = builder.start_with(RandomStep)
|
171
|
+
step1.when(0)
|
172
|
+
.then(TaskA)
|
173
|
+
.then(TaskB)
|
174
|
+
|
175
|
+
step1.when(1)
|
176
|
+
.then(TaskC)
|
177
|
+
.then(TaskD)
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
169
181
|
```
|
170
182
|
|
171
183
|
### Events
|
172
184
|
|
173
|
-
A workflow can also wait for an external event before proceeding. In the following example, the workflow will wait for an event called *"
|
174
|
-
|
175
|
-
```
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
}
|
185
|
+
A workflow can also wait for an external event before proceeding. In the following example, the workflow will wait for an event called *"my-event"* with a key of *0*. Once an external source has fired this event, the workflow will wake up and continue processing, passing the data generated by the event onto the next step.
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
class EventSample_Workflow
|
189
|
+
ID = 'event-sample'
|
190
|
+
VERSION = 1
|
191
|
+
DATA_CLASS = MyData
|
192
|
+
|
193
|
+
def build(builder)
|
194
|
+
builder
|
195
|
+
.start_with(HelloWorld)
|
196
|
+
.wait_for('my-event', '0')
|
197
|
+
.output(:my_value) { |step| step.event_data }
|
198
|
+
.then(CustomMessage)
|
199
|
+
.input(:message) {|data| "The event data is #{data.my_value}"}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
192
203
|
...
|
193
|
-
|
194
|
-
|
195
|
-
host.
|
204
|
+
# External events are published via the host
|
205
|
+
# All workflows that have subscribed to my-event 0, will be passed "hello"
|
206
|
+
host.publish_event('my-event', '0', 'hello')
|
196
207
|
```
|
197
208
|
|
198
209
|
### Host
|
199
210
|
|
200
211
|
The workflow host is the service responsible for executing workflows. It does this by polling the persistence provider for workflow instances that are ready to run, executes them and then passes them back to the persistence provider to by stored for the next time they are run. It is also responsible for publishing events to any workflows that may be waiting on one.
|
201
212
|
|
202
|
-
#### Setup
|
203
213
|
|
204
|
-
|
205
|
-
By default, it is configured with *MemoryPersistenceProvider* and *SingleNodeConcurrencyProvider* for testing purposes. You can also configure a DB persistence provider at this point.
|
214
|
+
#### Usage
|
206
215
|
|
207
|
-
|
208
|
-
services.AddWorkflow();
|
209
|
-
```
|
216
|
+
When your application starts, instantiate a *WorkflowHost*, register your workflow definitions and start it
|
210
217
|
|
211
|
-
#### Usage
|
212
218
|
|
213
|
-
|
219
|
+
```ruby
|
220
|
+
host = WorkflowRb::WorkflowHost.new
|
214
221
|
|
222
|
+
# register our workflows with the host
|
223
|
+
host.register_workflow(HelloWorld_Workflow)
|
215
224
|
|
216
|
-
|
217
|
-
|
218
|
-
host.RegisterWorkflow<HelloWorldWorkflow>();
|
219
|
-
host.Start();
|
225
|
+
# start the host
|
226
|
+
host.start
|
220
227
|
|
221
|
-
|
228
|
+
# start a new workflow
|
229
|
+
host.start_workflow('hello world', 1)
|
222
230
|
|
223
|
-
Console.ReadLine();
|
224
|
-
host.Stop();
|
225
231
|
```
|
226
232
|
|
227
233
|
|
@@ -231,10 +237,10 @@ Since workflows are typically long running processes, they will need to be persi
|
|
231
237
|
There are several persistence providers available as seperate Nuget packages.
|
232
238
|
|
233
239
|
* MemoryPersistenceProvider *(Default provider, for demo and testing purposes)*
|
234
|
-
* [MongoDB](
|
235
|
-
*
|
236
|
-
*
|
237
|
-
*
|
240
|
+
* [MongoDB](workflow_rb-mongo)
|
241
|
+
* SQL Server *(coming soon...)*
|
242
|
+
* PostgreSQL *(coming soon...)*
|
243
|
+
* Sqlite *(coming soon...)*
|
238
244
|
* Redis *(coming soon...)*
|
239
245
|
|
240
246
|
### Multi-node clusters
|
@@ -244,31 +250,28 @@ By default, the WorkflowHost service will run as a single node using the built-i
|
|
244
250
|
#### Queue Providers
|
245
251
|
|
246
252
|
* SingleNodeQueueProvider *(Default built-in provider)*
|
247
|
-
*
|
253
|
+
* RabbitMQ *(coming soon...)*
|
248
254
|
* Apache ZooKeeper *(coming soon...)*
|
249
255
|
* 0MQ *(coming soon...)*
|
250
256
|
|
251
257
|
#### Distributed lock managers
|
252
258
|
|
253
259
|
* SingleNodeLockProvider *(Default built-in provider)*
|
254
|
-
*
|
260
|
+
* Redis Redlock *(coming soon...)*
|
255
261
|
* Apache ZooKeeper *(coming soon...)*
|
256
262
|
|
257
263
|
|
258
264
|
## Samples
|
259
265
|
|
260
|
-
[Hello World](
|
261
|
-
|
262
|
-
[Multiple outcomes](src/samples/WorkflowCore.Sample06)
|
263
|
-
|
264
|
-
[Passing Data](src/samples/WorkflowCore.Sample03)
|
266
|
+
[Hello World](samples/sample01.rb)
|
265
267
|
|
266
|
-
[
|
268
|
+
[Multiple outcomes](samples/sample06.rb)
|
267
269
|
|
268
|
-
[
|
270
|
+
[Passing Data](samples/sample02.rb)
|
269
271
|
|
270
|
-
[
|
272
|
+
[Events](samples/sample04.rb)
|
271
273
|
|
274
|
+
[Deferred execution & re-entrant steps](samples/sample05.rb)
|
272
275
|
|
273
276
|
## Authors
|
274
277
|
|
data/lib/workflow_rb/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: workflow_rb
|
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
|
- Daniel Gerlag
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|