Skip to content

Commit 3738a2c

Browse files
authored
0.5.2. (#9)
1 parent 283834b commit 3738a2c

File tree

6 files changed

+133
-2
lines changed

6 files changed

+133
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.5.2
2+
3+
This version adds a possibility to stop a workflow machine. To stop a workflow machine, you should call the `tryStop()` method of the `WorkflowMachineInterpreter` class.
4+
15
## 0.5.1
26

37
This version adds a new feature to the `fork` activity. Now it's possible to skip all branches. The handler of the `fork` activity should return a value returned by the `skip()` function.

machine/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "sequential-workflow-machine",
33
"description": "Powerful sequential workflow machine for frontend and backend applications.",
4-
"version": "0.5.1",
4+
"version": "0.5.2",
55
"type": "module",
66
"main": "./lib/esm/index.js",
77
"types": "./lib/index.d.ts",

machine/src/activities/break-activity/break-activity.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ describe('BreakActivity', () => {
9898
const snapshot = interpreter.getSnapshot();
9999

100100
expect(snapshot.isFinished()).toBe(true);
101+
expect(snapshot.isInterrupted()).toBe(false);
102+
expect(snapshot.isFailed()).toBe(false);
101103
expect(snapshot.globalState.trace).toBe(
102104
'(condition)(decrement)(break)(condition)(decrement)(break)(condition)(decrement)(break)'
103105
);

machine/src/activities/fork-activity/fork-activity.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ describe('ForkActivity', () => {
112112
const snapshot = interpreter.getSnapshot();
113113

114114
expect(snapshot.isFinished()).toBe(true);
115+
expect(snapshot.isInterrupted()).toBe(false);
116+
expect(snapshot.isFailed()).toBe(false);
115117
expect(snapshot.globalState.message).toBe('(start)(true)(end)');
116118

117119
done();
@@ -131,6 +133,8 @@ describe('ForkActivity', () => {
131133
const snapshot = interpreter.getSnapshot();
132134

133135
expect(snapshot.isInterrupted()).toBe(true);
136+
expect(snapshot.isFinished()).toBe(false);
137+
expect(snapshot.isFailed()).toBe(false);
134138
expect(snapshot.globalState.message).toBe('(start)');
135139

136140
done();
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { Definition, SequentialStep, Step } from 'sequential-workflow-model';
2+
import { WorkflowMachineInterpreter } from './workflow-machine-interpreter';
3+
import { createActivitySet } from './core';
4+
import { createWorkflowMachineBuilder } from './workflow-machine-builder';
5+
import { createAtomActivityFromHandler, createLoopActivity } from './activities';
6+
7+
interface TestGlobalState {
8+
mode: string;
9+
value: number;
10+
}
11+
12+
const definition: Definition = {
13+
properties: {},
14+
sequence: [
15+
{
16+
id: '0xloop',
17+
componentType: 'container',
18+
name: 'loop',
19+
type: 'loop',
20+
properties: {},
21+
sequence: [
22+
{
23+
type: 'ping',
24+
componentType: 'task',
25+
name: 'ping',
26+
id: '0xping',
27+
properties: {}
28+
}
29+
]
30+
} as SequentialStep
31+
]
32+
};
33+
34+
const loopActivity = createLoopActivity<SequentialStep, TestGlobalState>('loop', {
35+
condition: async () => true,
36+
init: () => ({}),
37+
loopName: () => 'loop'
38+
});
39+
40+
const pingActivity = createAtomActivityFromHandler<Step, TestGlobalState>('ping', async (_, g) => {
41+
await sleep(2);
42+
g.value++;
43+
});
44+
45+
async function sleep(ms: number) {
46+
return new Promise(resolve => setTimeout(resolve, ms));
47+
}
48+
49+
describe('WorkflowMachineInterpreter', () => {
50+
describe('tryStop()', () => {
51+
let interpreter: WorkflowMachineInterpreter<TestGlobalState>;
52+
53+
beforeEach(() => {
54+
const activitySet = createActivitySet<TestGlobalState>([loopActivity, pingActivity]);
55+
const workflowMachine = createWorkflowMachineBuilder(activitySet);
56+
const machine = workflowMachine.build(definition);
57+
58+
interpreter = machine.create({
59+
init: () => ({
60+
mode: 'increment',
61+
value: 0
62+
})
63+
});
64+
interpreter.start();
65+
});
66+
67+
it('can stop from outside', done => {
68+
interpreter.onDone(() => {
69+
const context = interpreter.getSnapshot();
70+
71+
expect(context.isFailed()).toBe(false);
72+
expect(context.isInterrupted()).toBe(false);
73+
expect(context.isFinished()).toBe(false);
74+
done();
75+
});
76+
77+
setTimeout(() => {
78+
interpreter.tryStop();
79+
}, 100);
80+
});
81+
82+
it('can stop from onChange', done => {
83+
let onChangeCalledAfterStop = 0;
84+
85+
interpreter.onChange(() => {
86+
const snapshot = interpreter.getSnapshot();
87+
if (snapshot.globalState.value > 10) {
88+
interpreter.tryStop();
89+
onChangeCalledAfterStop++;
90+
}
91+
});
92+
interpreter.onDone(() => {
93+
const context = interpreter.getSnapshot();
94+
95+
expect(context.isFailed()).toBe(false);
96+
expect(context.isFinished()).toBe(false);
97+
expect(context.isInterrupted()).toBe(false);
98+
expect(onChangeCalledAfterStop).toBe(0);
99+
done();
100+
});
101+
});
102+
103+
it('cannot stop two times', () => {
104+
expect(interpreter.tryStop()).toBe(true);
105+
expect(interpreter.tryStop()).toBe(false);
106+
});
107+
});
108+
});

machine/src/workflow-machine-interpreter.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { InterpreterStatus } from 'xstate';
12
import { SequentialStateMachineInterpreter } from './types';
23
import { WorkflowMachineSnapshot } from './workflow-machine-snapshot';
34

@@ -15,7 +16,7 @@ export class WorkflowMachineInterpreter<GlobalState> {
1516
}
1617

1718
public onDone(callback: () => void): this {
18-
this.interpreter.onDone(callback);
19+
this.interpreter.onStop(callback);
1920
return this;
2021
}
2122

@@ -24,6 +25,18 @@ export class WorkflowMachineInterpreter<GlobalState> {
2425
return this;
2526
}
2627

28+
public isRunning(): boolean {
29+
return this.interpreter.status === InterpreterStatus.Running;
30+
}
31+
32+
public tryStop(): boolean {
33+
if (this.isRunning()) {
34+
this.interpreter.stop();
35+
return true;
36+
}
37+
return false;
38+
}
39+
2740
public sendSignal(signalName: string, params?: Record<string, unknown>): this {
2841
this.interpreter.send(signalName, params);
2942
return this;

0 commit comments

Comments
 (0)