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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/README.md +128 -125
  4. data/lib/workflow_rb/version.rb +1 -1
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db6ec565f41bd3aa0fb7185eb61d1bd564507b23
4
- data.tar.gz: 8819c1ff1c35e6805d9087ade26b5b6551cd5027
3
+ metadata.gz: cad4fe51a2b9a5d596418840c27400df4da2e0d8
4
+ data.tar.gz: 6b9803669daf8bb48231d2769b7e3a359d537d28
5
5
  SHA512:
6
- metadata.gz: 047385eea283a299a6fd81b661207a412bb7dc1072487d6b679d673cb5f5df2f25711aefb7fc1a103897ee55ba5d3bbe0c0eb24e5f1ccb34b66ed182dff52b3b
7
- data.tar.gz: 1673696f3d5fcb15ef57c32995854aefe70fdd25b023599f041674ebda50ae97ee2a5b8b0f6c510d59cbf6a18ccad222a6ca42f51a57a202e92ce28465185a77
6
+ metadata.gz: 0b08c328a31421b6fa0ad8bb7db5255b63a674fb3bddc278985ce659a348191f9fd6a0b70ed401df94e5388019e1c6a54bf17ab7f5232d80ccf52d3877472dd2
7
+ data.tar.gz: c5b62ff87e2671574c86219ac4cc1f0cb7ece19e0c8924cf26ff36ee21c98e53fa8c7443a3fb302f70fb4265605a38dc13a9f5c8848190a3c216aabf64383185
data/.gitignore CHANGED
@@ -8,4 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /.idea
11
- /workflow_rb-0.1.0.gem
11
+ /*.gem
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 12 hours, while setting the persistence_data to *'something'*. 12 hours 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
- ```C#
87
- public class SleepStep : StepBody
88
- {
89
- public override ExecutionResult Run(IStepExecutionContext context)
90
- {
91
- if (context.PersistenceData == null)
92
- return ExecutionResult.Sleep(Timespan.FromHours(12), new Object());
93
- else
94
- return ExecutionResult.Next();
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 intented to be a blackbox, 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.
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 properties on the custom data class.
104
-
105
- ```C#
106
- //Our workflow step with inputs and outputs
107
- public class AddNumbers : StepBody
108
- {
109
- public int Input1 { get; set; }
110
-
111
- public int Input2 { get; set; }
112
-
113
- public int Output { get; set; }
114
-
115
- public override ExecutionResult Run(IStepExecutionContext context)
116
- {
117
- Output = (Input1 + Input2);
118
- return ExecutionResult.Next();
119
- }
120
- }
121
-
122
- //Our class to define the internal data of our workflow
123
- public class MyDataClass
124
- {
125
- public int Value1 { get; set; }
126
- public int Value2 { get; set; }
127
- public int Value3 { get; set; }
128
- }
129
-
130
- //Our workflow definition with strongly typed internal data and mapped inputs & outputs
131
- public class PassingDataWorkflow : IWorkflow<MyDataClass>
132
- {
133
- public void Build(IWorkflowBuilder<MyDataClass> builder)
134
- {
135
- builder
136
- .StartWith<AddNumbers>()
137
- .Input(step => step.Input1, data => data.Value1)
138
- .Input(step => step.Input2, data => data.Value2)
139
- .Output(data => data.Value3, step => step.Output)
140
- .Then<CustomMessage>()
141
- .Input(step => step.Message, data => "The answer is " + data.Value3.ToString());
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
- ```C#
153
- public class MultipleOutcomeWorkflow : IWorkflow
154
- {
155
- public void Build(IWorkflowBuilder<object> builder)
156
- {
157
- builder
158
- .StartWith<RandomOutput>(x => x.Name("Random Step"))
159
- .When(0)
160
- .Then<TaskA>()
161
- .Then<TaskB>()
162
- .End<RandomOutput>("Random Step")
163
- .When(1)
164
- .Then<TaskC>()
165
- .Then<TaskD>()
166
- .End<RandomOutput>("Random Step");
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 *"MyEvent"* with a key of *0*. Once an external source has fired this event, the workflow will wake up and continute processing, passing the data generated by the event onto the next step.
174
-
175
- ```C#
176
- public class EventSampleWorkflow : IWorkflow<MyDataClass>
177
- {
178
- public void Build(IWorkflowBuilder<MyDataClass> builder)
179
- {
180
- builder
181
- .StartWith(context =>
182
- {
183
- Console.WriteLine("workflow started");
184
- return ExecutionResult.Next();
185
- })
186
- .WaitFor("MyEvent", "0")
187
- .Output(data => data.Value, step => step.EventData)
188
- .Then<CustomMessage>()
189
- .Input(step => step.Message, data => "The data from the event is " + data.Value);
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
- //External events are published via the host
194
- //All workflows that have subscribed to MyEvent 0, will be passed "hello"
195
- host.PublishEvent("MyEvent", "0", "hello");
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
- Use the *AddWorkflow* extension method for *IServiceCollection* to configure the workflow host upon startup of your application.
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
- ```C#
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
- When your application starts, grab the workflow host from the built-in dependency injection framework *IServiceProvider*. Make sure you call *RegisterWorkflow*, so that the workflow host knows about all your workflows, and then call *Start()* to fire up the thread pool that executes workflows. Use the *StartWorkflow* method to initiate a new instance of a particular workflow.
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
- ```C#
217
- var host = serviceProvider.GetService<IWorkflowHost>();
218
- host.RegisterWorkflow<HelloWorldWorkflow>();
219
- host.Start();
225
+ # start the host
226
+ host.start
220
227
 
221
- host.StartWorkflow("HelloWorld", 1, null);
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](src/providers/WorkflowCore.Persistence.MongoDB)
235
- * [SQL Server](src/providers/WorkflowCore.Persistence.SqlServer)
236
- * [PostgreSQL](src/providers/WorkflowCore.Persistence.PostgreSQL)
237
- * [Sqlite](src/providers/WorkflowCore.Persistence.Sqlite)
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
- * [RabbitMQ](src/providers/WorkflowCore.QueueProviders.RabbitMQ)
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
- * [Redis Redlock](src/providers/WorkflowCore.LockProviders.Redlock)
260
+ * Redis Redlock *(coming soon...)*
255
261
  * Apache ZooKeeper *(coming soon...)*
256
262
 
257
263
 
258
264
  ## Samples
259
265
 
260
- [Hello World](src/samples/WorkflowCore.Sample01)
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
- [Events](src/samples/WorkflowCore.Sample04)
268
+ [Multiple outcomes](samples/sample06.rb)
267
269
 
268
- [Deferred execution & re-entrant steps](src/samples/WorkflowCore.Sample05)
270
+ [Passing Data](samples/sample02.rb)
269
271
 
270
- [Looping](src/samples/WorkflowCore.Sample02)
272
+ [Events](samples/sample04.rb)
271
273
 
274
+ [Deferred execution & re-entrant steps](samples/sample05.rb)
272
275
 
273
276
  ## Authors
274
277
 
@@ -1,3 +1,3 @@
1
1
  module WorkflowRb
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
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.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-10 00:00:00.000000000 Z
11
+ date: 2016-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler