-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from danielgerlag/parallel
Parallel sequences
- Loading branch information
Showing
16 changed files
with
433 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { WorkflowHost, WorkflowBuilder, WorkflowStatus, WorkflowBase, StepBody, StepExecutionContext, ExecutionResult, WorkflowInstance, configureWorkflow, ConsoleLogger } from "../../src"; | ||
import { MemoryPersistenceProvider } from "../../src/services/memory-persistence-provider"; | ||
import { spinWaitCallback, spinWait } from "../helpers/spin-wait"; | ||
|
||
describe("parallel sequences", () => { | ||
|
||
let workflowScope = { | ||
step0Ticker: 0, | ||
step1Ticker: 0, | ||
step2Ticker: 0, | ||
step3Ticker: 0 | ||
} | ||
|
||
class Step0 extends StepBody { | ||
public run(context: StepExecutionContext): Promise<ExecutionResult> { | ||
workflowScope.step0Ticker++; | ||
return ExecutionResult.next(); | ||
} | ||
} | ||
|
||
class Step1 extends StepBody { | ||
public run(context: StepExecutionContext): Promise<ExecutionResult> { | ||
workflowScope.step1Ticker++; | ||
return ExecutionResult.next(); | ||
} | ||
} | ||
|
||
class Step2 extends StepBody { | ||
public run(context: StepExecutionContext): Promise<ExecutionResult> { | ||
workflowScope.step2Ticker++; | ||
return ExecutionResult.next(); | ||
} | ||
} | ||
|
||
class Step3 extends StepBody { | ||
public run(context: StepExecutionContext): Promise<ExecutionResult> { | ||
workflowScope.step3Ticker++; | ||
return ExecutionResult.next(); | ||
} | ||
} | ||
|
||
class Parallel_Workflow implements WorkflowBase<any> { | ||
public id: string = "parallel-workflow"; | ||
public version: number = 1; | ||
|
||
public build(builder: WorkflowBuilder<any>) { | ||
builder | ||
.startWith(Step0) | ||
.parallel() | ||
.do(branch1 => branch1 | ||
.startWith(Step1) | ||
.waitFor("my-event", data => "0") | ||
) | ||
.do(branch2 => branch2 | ||
.startWith(Step2) | ||
) | ||
.join() | ||
.then(Step3); | ||
} | ||
} | ||
|
||
let workflowId = null; | ||
let instance = null; | ||
let persistence = new MemoryPersistenceProvider(); | ||
let config = configureWorkflow(); | ||
config.useLogger(new ConsoleLogger()); | ||
config.usePersistence(persistence); | ||
let host = config.getHost(); | ||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; | ||
|
||
beforeAll(async (done) => { | ||
host.registerWorkflow(Parallel_Workflow); | ||
await host.start(); | ||
|
||
workflowId = await host.startWorkflow("parallel-workflow", 1, null); | ||
|
||
await spinWait(async () => { | ||
let subs = await persistence.getSubscriptions("my-event", "0", new Date()); | ||
return (subs.length > 0); | ||
}); | ||
|
||
expect(workflowScope.step0Ticker).toBe(1); | ||
expect(workflowScope.step1Ticker).toBe(1); | ||
expect(workflowScope.step2Ticker).toBe(1); | ||
expect(workflowScope.step3Ticker).toBe(0); | ||
|
||
await host.publishEvent("my-event", "0", "Pass", new Date()); | ||
|
||
spinWaitCallback(async () => { | ||
instance = await persistence.getWorkflowInstance(workflowId); | ||
return (instance.status != WorkflowStatus.Runnable); | ||
}, done); | ||
}); | ||
|
||
afterAll(() => { | ||
host.stop(); | ||
}); | ||
|
||
it("should be marked as complete", function() { | ||
expect(instance.status).toBe(WorkflowStatus.Complete); | ||
}); | ||
|
||
it("should have taken correct execution path", function() { | ||
expect(workflowScope.step0Ticker).toBe(1); | ||
expect(workflowScope.step1Ticker).toBe(1); | ||
expect(workflowScope.step2Ticker).toBe(1); | ||
expect(workflowScope.step3Ticker).toBe(1); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from "./fluent-builders/workflow-builder"; | ||
export * from "./fluent-builders/step-builder"; | ||
export * from "./fluent-builders/parallel-step-builder"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { StepBody, InlineStepBody } from "../abstractions"; | ||
import { WorkflowDefinition, WorkflowStepBase, WorkflowStep, StepOutcome, StepExecutionContext, ExecutionResult, WorkflowErrorHandling } from "../models"; | ||
import { WorkflowBuilder } from "./workflow-builder"; | ||
import { StepBuilder } from "./step-builder"; | ||
import { Sequence } from "../primitives"; | ||
|
||
export class ParallelStepBuilder<TData, TStepBody extends StepBody> { | ||
|
||
private workflowBuilder: WorkflowBuilder<TData>; | ||
private referenceBuilder: StepBuilder<Sequence, TData>; | ||
private step: WorkflowStep<TStepBody>; | ||
|
||
constructor(workflowBuilder: WorkflowBuilder<TData>, step: WorkflowStep<TStepBody>, refBuilder: StepBuilder<Sequence, TData>) { | ||
this.workflowBuilder = workflowBuilder; | ||
this.step = step; | ||
this.referenceBuilder = refBuilder; | ||
} | ||
|
||
public do(builder: (then: WorkflowBuilder<TData>) => void): ParallelStepBuilder<TData, TStepBody> { | ||
let lastStep = this.workflowBuilder.lastStep(); | ||
builder(this.workflowBuilder); | ||
this.step.children.push(lastStep + 1); //TODO: make more elegant | ||
return this; | ||
} | ||
|
||
public join(): StepBuilder<Sequence, TData> { | ||
return this.referenceBuilder; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { ExecutionResult, StepExecutionContext, ContainerData } from "../models"; | ||
import { StepBody } from "../abstractions"; | ||
import { ContainerStepBody } from "./container-step-body"; | ||
|
||
export class Sequence extends ContainerStepBody { | ||
|
||
public run(context: StepExecutionContext): Promise<ExecutionResult> { | ||
|
||
if (!context.persistenceData) { | ||
let containerData = new ContainerData(); | ||
containerData.childrenActive = true; | ||
return ExecutionResult.branch([null], containerData); | ||
} | ||
|
||
if ((context.persistenceData as ContainerData).childrenActive) { | ||
let complete: boolean = true; | ||
|
||
for(let childId of context.pointer.children) | ||
complete = complete && this.isBranchComplete(context.workflow.executionPointers, childId); | ||
|
||
if (complete) | ||
return ExecutionResult.next(); | ||
else | ||
return ExecutionResult.persist(context.persistenceData); | ||
} | ||
|
||
return ExecutionResult.persist(context.persistenceData); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Workflow ES 2.2 | ||
|
||
### Parallel Sequences | ||
|
||
Run several sequences of steps in parallel | ||
|
||
```javascript | ||
class Parallel_Workflow { | ||
|
||
build(builder) { | ||
builder | ||
.startWith(SayHello) | ||
.parallel() | ||
.do(branch1 => branch1 | ||
.startWith(PrintMessage) | ||
.input((step, data) => step.message = "Running in branch 1") | ||
.delay(data => 5000) | ||
.then(DoSomething) | ||
) | ||
.do(branch2 => branch2 | ||
.startWith(PrintMessage) | ||
.input((step, data) => step.message = "Running in branch 2") | ||
) | ||
.do(branch3 => branch3 | ||
.startWith(PrintMessage) | ||
.input((step, data) => step.message = "Running in branch 3") | ||
) | ||
.join() | ||
.then(SayGoodbye); | ||
} | ||
} | ||
``` |
Oops, something went wrong.