@logicflow/engine 0.0.1 → 0.0.3
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.
- package/CHANGELOG.md +35 -0
- package/README.md +3 -15
- package/cjs/FlowModel.js +77 -55
- package/cjs/Scheduler.js +68 -96
- package/cjs/constant/constant.js +8 -8
- package/cjs/expression/browserVm.js +30 -22
- package/cjs/expression/nodeVm.js +1 -1
- package/cjs/index.js +34 -9
- package/cjs/nodes/BaseNode.js +10 -10
- package/cjs/recorder/index.js +33 -17
- package/cjs/util/ID.js +7 -3
- package/es/FlowModel.d.ts +59 -19
- package/es/FlowModel.js +77 -55
- package/es/Scheduler.d.ts +26 -15
- package/es/Scheduler.js +69 -97
- package/es/constant/constant.d.ts +1 -1
- package/es/constant/constant.js +7 -7
- package/es/expression/browserVm.d.ts +3 -1
- package/es/expression/browserVm.js +28 -22
- package/es/expression/nodeVm.js +1 -1
- package/es/index.d.ts +22 -11
- package/es/index.js +34 -9
- package/es/nodes/BaseNode.d.ts +19 -8
- package/es/nodes/BaseNode.js +11 -11
- package/es/recorder/index.d.ts +8 -4
- package/es/recorder/index.js +33 -17
- package/es/util/ID.d.ts +2 -1
- package/es/util/ID.js +6 -2
- package/lib/main.js +1 -1
- package/package.json +4 -1
- package/types/EventEmitter.d.ts +0 -7
- package/types/FlowModel.d.ts +0 -104
- package/types/Scheduler.d.ts +0 -51
- package/types/constant/LogCode.d.ts +0 -12
- package/types/constant/constant.d.ts +0 -14
- package/types/expression/browserVm.d.ts +0 -2
- package/types/expression/index.d.ts +0 -2
- package/types/expression/nodeVm.d.ts +0 -2
- package/types/index.d.ts +0 -47
- package/types/nodes/BaseNode.d.ts +0 -109
- package/types/nodes/StartNode.d.ts +0 -5
- package/types/nodes/TaskNode.d.ts +0 -5
- package/types/recorder/index.d.ts +0 -9
- package/types/util/ID.d.ts +0 -2
- package/types/util/global.d.ts +0 -5
- package/types/util/storage.d.ts +0 -6
package/cjs/index.js
CHANGED
|
@@ -54,11 +54,12 @@ exports.StartNode = StartNode_1.default;
|
|
|
54
54
|
var TaskNode_1 = require("./nodes/TaskNode");
|
|
55
55
|
exports.TaskNode = TaskNode_1.default;
|
|
56
56
|
var recorder_1 = require("./recorder");
|
|
57
|
+
var ID_1 = require("./util/ID");
|
|
57
58
|
var Engine = /** @class */ (function () {
|
|
58
|
-
function Engine() {
|
|
59
|
+
function Engine(options) {
|
|
59
60
|
this.nodeModelMap = new Map();
|
|
61
|
+
this.id = ID_1.createEngineId();
|
|
60
62
|
this.recorder = new recorder_1.default();
|
|
61
|
-
// register node
|
|
62
63
|
this.register({
|
|
63
64
|
type: StartNode_1.default.nodeTypeName,
|
|
64
65
|
model: StartNode_1.default,
|
|
@@ -67,10 +68,11 @@ var Engine = /** @class */ (function () {
|
|
|
67
68
|
type: TaskNode_1.default.nodeTypeName,
|
|
68
69
|
model: TaskNode_1.default,
|
|
69
70
|
});
|
|
71
|
+
this.context = (options === null || options === void 0 ? void 0 : options.context) || {};
|
|
70
72
|
}
|
|
71
73
|
/**
|
|
72
74
|
* 注册节点
|
|
73
|
-
* @param nodeConfig { type: 'custom-node', model:
|
|
75
|
+
* @param nodeConfig { type: 'custom-node', model: NodeClass }
|
|
74
76
|
*/
|
|
75
77
|
Engine.prototype.register = function (nodeConfig) {
|
|
76
78
|
this.nodeModelMap.set(nodeConfig.type, nodeConfig.model);
|
|
@@ -80,8 +82,8 @@ var Engine = /** @class */ (function () {
|
|
|
80
82
|
* 注意:由于执行记录不会主动删除,所以需要自行清理。
|
|
81
83
|
* nodejs环境建议自定义为持久化存储。
|
|
82
84
|
* engine.setCustomRecorder({
|
|
83
|
-
* async
|
|
84
|
-
* async getTask(
|
|
85
|
+
* async addActionRecord(task) {}
|
|
86
|
+
* async getTask(actionId) {}
|
|
85
87
|
* async getExecutionTasks(executionId) {}
|
|
86
88
|
* clear() {}
|
|
87
89
|
* });
|
|
@@ -93,11 +95,11 @@ var Engine = /** @class */ (function () {
|
|
|
93
95
|
* 加载流程图数据
|
|
94
96
|
*/
|
|
95
97
|
Engine.prototype.load = function (_a) {
|
|
96
|
-
var graphData = _a.graphData, _b = _a.startNodeType, startNodeType = _b === void 0 ? 'StartNode' : _b, _c = _a.globalData, globalData = _c === void 0 ? {} : _c
|
|
98
|
+
var graphData = _a.graphData, _b = _a.startNodeType, startNodeType = _b === void 0 ? 'StartNode' : _b, _c = _a.globalData, globalData = _c === void 0 ? {} : _c;
|
|
97
99
|
this.flowModel = new FlowModel_1.default({
|
|
98
100
|
nodeModelMap: this.nodeModelMap,
|
|
99
101
|
recorder: this.recorder,
|
|
100
|
-
context: context,
|
|
102
|
+
context: this.context,
|
|
101
103
|
globalData: globalData,
|
|
102
104
|
startNodeType: startNodeType,
|
|
103
105
|
});
|
|
@@ -124,6 +126,12 @@ var Engine = /** @class */ (function () {
|
|
|
124
126
|
});
|
|
125
127
|
});
|
|
126
128
|
};
|
|
129
|
+
/**
|
|
130
|
+
* 恢复执行
|
|
131
|
+
* 注意此方法只能恢复节点后面的执行,不能恢复流程其他分支的执行。
|
|
132
|
+
* 同理,中断执行也只能中断节点后面的执行,不会中断其他分支的执行。
|
|
133
|
+
* 在实际项目中,如果存在中断节点,建议流程所有的节点都是排他网关,这样可以保证执行的过程不存在分支。
|
|
134
|
+
*/
|
|
127
135
|
Engine.prototype.resume = function (resumeParam) {
|
|
128
136
|
return __awaiter(this, void 0, void 0, function () {
|
|
129
137
|
var _this = this;
|
|
@@ -143,18 +151,35 @@ var Engine = /** @class */ (function () {
|
|
|
143
151
|
var tasks, records, i;
|
|
144
152
|
return __generator(this, function (_a) {
|
|
145
153
|
switch (_a.label) {
|
|
146
|
-
case 0: return [4 /*yield*/, this.recorder.
|
|
154
|
+
case 0: return [4 /*yield*/, this.recorder.getExecutionActions(executionId)];
|
|
147
155
|
case 1:
|
|
148
156
|
tasks = _a.sent();
|
|
157
|
+
if (!tasks) {
|
|
158
|
+
return [2 /*return*/, null];
|
|
159
|
+
}
|
|
149
160
|
records = [];
|
|
150
161
|
for (i = 0; i < tasks.length; i++) {
|
|
151
|
-
records.push(this.recorder.
|
|
162
|
+
records.push(this.recorder.getActionRecord(tasks[i]));
|
|
152
163
|
}
|
|
153
164
|
return [2 /*return*/, Promise.all(records)];
|
|
154
165
|
}
|
|
155
166
|
});
|
|
156
167
|
});
|
|
157
168
|
};
|
|
169
|
+
Engine.prototype.getGlobalData = function () {
|
|
170
|
+
var _a;
|
|
171
|
+
return (_a = this.flowModel) === null || _a === void 0 ? void 0 : _a.globalData;
|
|
172
|
+
};
|
|
173
|
+
Engine.prototype.setGlobalData = function (data) {
|
|
174
|
+
if (this.flowModel) {
|
|
175
|
+
this.flowModel.globalData = data;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
Engine.prototype.updateGlobalData = function (data) {
|
|
179
|
+
if (this.flowModel) {
|
|
180
|
+
Object.assign(this.flowModel.globalData, data);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
158
183
|
return Engine;
|
|
159
184
|
}());
|
|
160
185
|
exports.Engine = Engine;
|
package/cjs/nodes/BaseNode.js
CHANGED
|
@@ -67,13 +67,13 @@ var BaseNode = /** @class */ (function () {
|
|
|
67
67
|
this.incoming = nodeConfig.incoming;
|
|
68
68
|
this.nodeId = nodeConfig.id;
|
|
69
69
|
this.type = nodeConfig.type;
|
|
70
|
-
this.properties = nodeConfig.properties;
|
|
70
|
+
this.properties = nodeConfig.properties || {};
|
|
71
71
|
this.context = context;
|
|
72
72
|
this.globalData = globalData;
|
|
73
73
|
this.baseType = 'base';
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
|
-
* 节点的每一次执行都会生成一个唯一的
|
|
76
|
+
* 节点的每一次执行都会生成一个唯一的actionId
|
|
77
77
|
*/
|
|
78
78
|
BaseNode.prototype.execute = function (params) {
|
|
79
79
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -82,18 +82,18 @@ var BaseNode = /** @class */ (function () {
|
|
|
82
82
|
switch (_a.label) {
|
|
83
83
|
case 0: return [4 /*yield*/, this.action({
|
|
84
84
|
executionId: params.executionId,
|
|
85
|
-
|
|
85
|
+
actionId: params.actionId,
|
|
86
86
|
nodeId: this.nodeId,
|
|
87
87
|
})];
|
|
88
88
|
case 1:
|
|
89
89
|
r = _a.sent();
|
|
90
|
-
if (!(!r || r.status === constant_1.
|
|
90
|
+
if (!(!r || r.status === constant_1.ActionStatus.SUCCESS)) return [3 /*break*/, 3];
|
|
91
91
|
return [4 /*yield*/, this.getOutgoing()];
|
|
92
92
|
case 2:
|
|
93
93
|
outgoing = _a.sent();
|
|
94
94
|
params.next({
|
|
95
95
|
executionId: params.executionId,
|
|
96
|
-
|
|
96
|
+
actionId: params.actionId,
|
|
97
97
|
nodeId: this.nodeId,
|
|
98
98
|
nodeType: this.type,
|
|
99
99
|
properties: this.properties,
|
|
@@ -104,7 +104,7 @@ var BaseNode = /** @class */ (function () {
|
|
|
104
104
|
status: r && r.status,
|
|
105
105
|
detail: r && r.detail,
|
|
106
106
|
executionId: params.executionId,
|
|
107
|
-
|
|
107
|
+
actionId: params.actionId,
|
|
108
108
|
nodeId: this.nodeId,
|
|
109
109
|
nodeType: this.type,
|
|
110
110
|
properties: this.properties,
|
|
@@ -128,14 +128,14 @@ var BaseNode = /** @class */ (function () {
|
|
|
128
128
|
return [4 /*yield*/, this.onResume({
|
|
129
129
|
executionId: params.executionId,
|
|
130
130
|
nodeId: params.nodeId,
|
|
131
|
-
|
|
131
|
+
actionId: params.actionId,
|
|
132
132
|
data: params.data,
|
|
133
133
|
})];
|
|
134
134
|
case 2:
|
|
135
135
|
_a.sent();
|
|
136
136
|
params.next({
|
|
137
137
|
executionId: params.executionId,
|
|
138
|
-
|
|
138
|
+
actionId: params.actionId,
|
|
139
139
|
nodeId: this.nodeId,
|
|
140
140
|
nodeType: this.type,
|
|
141
141
|
properties: this.properties,
|
|
@@ -213,7 +213,7 @@ var BaseNode = /** @class */ (function () {
|
|
|
213
213
|
* 节点的执行逻辑
|
|
214
214
|
* @overridable 可以自定义节点重写此方法。
|
|
215
215
|
* @param params.executionId 流程执行记录ID
|
|
216
|
-
* @param params.
|
|
216
|
+
* @param params.actionId 此节点执行记录ID
|
|
217
217
|
* @param params.nodeId 节点ID
|
|
218
218
|
*/
|
|
219
219
|
BaseNode.prototype.action = function (params) {
|
|
@@ -227,7 +227,7 @@ var BaseNode = /** @class */ (function () {
|
|
|
227
227
|
* 节点的重新恢复执行逻辑
|
|
228
228
|
* @overridable 可以自定义节点重写此方法。
|
|
229
229
|
* @param params.executionId 流程执行记录ID
|
|
230
|
-
* @param params.
|
|
230
|
+
* @param params.actionId 此节点执行记录ID
|
|
231
231
|
* @param params.nodeId 节点ID
|
|
232
232
|
*/
|
|
233
233
|
BaseNode.prototype.onResume = function (params) {
|
package/cjs/recorder/index.js
CHANGED
|
@@ -38,13 +38,18 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
var storage_1 = require("../util/storage");
|
|
40
40
|
var LOGICFLOW_ENGINE_INSTANCES = 'LOGICFLOW_ENGINE_INSTANCES';
|
|
41
|
+
var MAX_RECORDER = 100;
|
|
41
42
|
var Recorder = /** @class */ (function () {
|
|
42
43
|
function Recorder() {
|
|
44
|
+
this.maxRecorder = MAX_RECORDER;
|
|
43
45
|
}
|
|
46
|
+
Recorder.prototype.setMaxRecorderNumber = function (maxRecorder) {
|
|
47
|
+
this.maxRecorder = maxRecorder;
|
|
48
|
+
};
|
|
44
49
|
/*
|
|
45
|
-
* @param {Object}
|
|
50
|
+
* @param {Object} action
|
|
46
51
|
* {
|
|
47
|
-
*
|
|
52
|
+
* actionId: '',
|
|
48
53
|
* nodeId: '',
|
|
49
54
|
* executionId: '',
|
|
50
55
|
* nodeType: '',
|
|
@@ -52,34 +57,34 @@ var Recorder = /** @class */ (function () {
|
|
|
52
57
|
* properties: {},
|
|
53
58
|
* }
|
|
54
59
|
*/
|
|
55
|
-
Recorder.prototype.
|
|
60
|
+
Recorder.prototype.addActionRecord = function (action) {
|
|
56
61
|
return __awaiter(this, void 0, void 0, function () {
|
|
57
|
-
var executionId,
|
|
62
|
+
var executionId, actionId, instanceData;
|
|
58
63
|
return __generator(this, function (_a) {
|
|
59
64
|
switch (_a.label) {
|
|
60
65
|
case 0:
|
|
61
|
-
executionId =
|
|
62
|
-
return [4 /*yield*/, this.
|
|
66
|
+
executionId = action.executionId, actionId = action.actionId;
|
|
67
|
+
return [4 /*yield*/, this.getExecutionActions(executionId)];
|
|
63
68
|
case 1:
|
|
64
69
|
instanceData = _a.sent();
|
|
65
70
|
if (!instanceData) {
|
|
66
71
|
this.pushExecution(executionId);
|
|
67
72
|
}
|
|
68
|
-
this.
|
|
69
|
-
storage_1.default.setItem(
|
|
73
|
+
this.pushActionToExecution(executionId, actionId);
|
|
74
|
+
storage_1.default.setItem(actionId, action);
|
|
70
75
|
return [2 /*return*/];
|
|
71
76
|
}
|
|
72
77
|
});
|
|
73
78
|
});
|
|
74
79
|
};
|
|
75
|
-
Recorder.prototype.
|
|
80
|
+
Recorder.prototype.getActionRecord = function (actionId) {
|
|
76
81
|
return __awaiter(this, void 0, void 0, function () {
|
|
77
82
|
return __generator(this, function (_a) {
|
|
78
|
-
return [2 /*return*/, storage_1.default.getItem(
|
|
83
|
+
return [2 /*return*/, storage_1.default.getItem(actionId)];
|
|
79
84
|
});
|
|
80
85
|
});
|
|
81
86
|
};
|
|
82
|
-
Recorder.prototype.
|
|
87
|
+
Recorder.prototype.getExecutionActions = function (executionId) {
|
|
83
88
|
return __awaiter(this, void 0, void 0, function () {
|
|
84
89
|
return __generator(this, function (_a) {
|
|
85
90
|
return [2 /*return*/, storage_1.default.getItem(executionId)];
|
|
@@ -91,21 +96,32 @@ var Recorder = /** @class */ (function () {
|
|
|
91
96
|
instance.forEach(function (executionId) {
|
|
92
97
|
storage_1.default.removeItem(executionId);
|
|
93
98
|
var instanceData = storage_1.default.getItem(executionId) || [];
|
|
94
|
-
instanceData.forEach(function (
|
|
95
|
-
storage_1.default.removeItem(
|
|
99
|
+
instanceData.forEach(function (actionId) {
|
|
100
|
+
storage_1.default.removeItem(actionId);
|
|
96
101
|
});
|
|
97
102
|
});
|
|
98
103
|
storage_1.default.removeItem(LOGICFLOW_ENGINE_INSTANCES);
|
|
99
104
|
};
|
|
100
105
|
Recorder.prototype.pushExecution = function (executionId) {
|
|
101
106
|
var instance = storage_1.default.getItem(LOGICFLOW_ENGINE_INSTANCES) || [];
|
|
107
|
+
if (instance.length >= this.maxRecorder) {
|
|
108
|
+
var removeItem = instance.shift();
|
|
109
|
+
this.popExecution(removeItem);
|
|
110
|
+
}
|
|
102
111
|
instance.push(executionId);
|
|
103
112
|
storage_1.default.setItem(LOGICFLOW_ENGINE_INSTANCES, instance);
|
|
104
113
|
};
|
|
105
|
-
Recorder.prototype.
|
|
106
|
-
var
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
Recorder.prototype.popExecution = function (executionId) {
|
|
115
|
+
var instanceData = storage_1.default.getItem(executionId) || [];
|
|
116
|
+
instanceData.forEach(function (actionId) {
|
|
117
|
+
storage_1.default.removeItem(actionId);
|
|
118
|
+
});
|
|
119
|
+
storage_1.default.removeItem(executionId);
|
|
120
|
+
};
|
|
121
|
+
Recorder.prototype.pushActionToExecution = function (executionId, actionId) {
|
|
122
|
+
var actions = storage_1.default.getItem(executionId) || [];
|
|
123
|
+
actions.push(actionId);
|
|
124
|
+
storage_1.default.setItem(executionId, actions);
|
|
109
125
|
};
|
|
110
126
|
return Recorder;
|
|
111
127
|
}());
|
package/cjs/util/ID.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.createEngineId = exports.createActionId = exports.createExecId = void 0;
|
|
4
4
|
var uuid_1 = require("uuid");
|
|
5
5
|
exports.createExecId = function () {
|
|
6
6
|
var uuid = uuid_1.v4();
|
|
7
7
|
return "exec-" + uuid;
|
|
8
8
|
};
|
|
9
|
-
exports.
|
|
9
|
+
exports.createActionId = function () {
|
|
10
10
|
var uuid = uuid_1.v4();
|
|
11
|
-
return "
|
|
11
|
+
return "action-" + uuid;
|
|
12
|
+
};
|
|
13
|
+
exports.createEngineId = function () {
|
|
14
|
+
var uuid = uuid_1.v4();
|
|
15
|
+
return "engine-" + uuid;
|
|
12
16
|
};
|
package/es/FlowModel.d.ts
CHANGED
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
import type { NodeConfig, NodeConstructor } from './nodes/BaseNode';
|
|
2
2
|
import type Recorder from './recorder';
|
|
3
3
|
import Scheduler from './Scheduler';
|
|
4
|
-
import type {
|
|
4
|
+
import type { ActionParam } from './types.d';
|
|
5
5
|
export declare type FlowResult = {
|
|
6
6
|
result?: Record<string, any>;
|
|
7
|
-
} &
|
|
8
|
-
export declare type
|
|
7
|
+
} & ActionParam;
|
|
8
|
+
export declare type ActionParams = {
|
|
9
9
|
executionId?: string;
|
|
10
|
-
|
|
10
|
+
actionId?: string;
|
|
11
11
|
nodeId?: string;
|
|
12
|
-
data?: Record<string, any>;
|
|
13
12
|
};
|
|
14
13
|
export declare type ExecParams = {
|
|
15
14
|
callback?: (result: FlowResult) => void;
|
|
16
15
|
onError?: (error: Error) => void;
|
|
17
|
-
} &
|
|
16
|
+
} & ActionParams;
|
|
18
17
|
export default class FlowModel {
|
|
19
18
|
/**
|
|
20
19
|
* 流程支持的节点类型
|
|
21
20
|
*/
|
|
22
21
|
nodeModelMap: Map<string, NodeConstructor>;
|
|
23
|
-
/**
|
|
24
|
-
* 每一次执行流程都会生成一个唯一的executionId。
|
|
25
|
-
*/
|
|
26
|
-
executionId: string;
|
|
27
22
|
/**
|
|
28
23
|
* 调度器,用于调度节点的执行。
|
|
29
24
|
*/
|
|
@@ -31,7 +26,7 @@ export default class FlowModel {
|
|
|
31
26
|
/**
|
|
32
27
|
* 待执行的队列,当流程正在执行时,如果再次触发执行。那么会将执行参数放入到队列中,等待上一次执行完成后再执行。
|
|
33
28
|
*/
|
|
34
|
-
|
|
29
|
+
executeList: ExecParams[];
|
|
35
30
|
/**
|
|
36
31
|
* 当前正在执行。当监听到调度器执行完成时,出触发执行参数中的回调,告知外部执行完成。
|
|
37
32
|
*/
|
|
@@ -76,29 +71,74 @@ export default class FlowModel {
|
|
|
76
71
|
startNodeType?: string;
|
|
77
72
|
});
|
|
78
73
|
setStartNodeType(startNodeType: any): void;
|
|
79
|
-
load(graphData: any): void;
|
|
80
74
|
/**
|
|
81
|
-
*
|
|
82
|
-
* 同一次执行,这次执行内部的节点执行顺序为并行。
|
|
83
|
-
* 多次执行,多次执行之间为串行。
|
|
84
|
-
* 允许一个流程多次执行,效率更高。
|
|
75
|
+
* 解析LogicFlow图数据,将nodes和edges转换成节点格式。
|
|
85
76
|
* 例如:
|
|
77
|
+
* graphData: {
|
|
78
|
+
* nodes: [
|
|
79
|
+
* { id: 'node1', type: 'StartNode', properties: {} },
|
|
80
|
+
* { id: 'node2', type: 'TaskNode', properties: {} },
|
|
81
|
+
* ],
|
|
82
|
+
* edges: [
|
|
83
|
+
* { id: 'edge1', sourceNodeId: 'node1', targetNodeId: 'node2', properties: {} },
|
|
84
|
+
* ]
|
|
85
|
+
* }
|
|
86
|
+
* 转换成:
|
|
87
|
+
* nodeConfigMap: {
|
|
88
|
+
* node1: {
|
|
89
|
+
* id: 'node1',
|
|
90
|
+
* type: 'StartNode',
|
|
91
|
+
* properties: {},
|
|
92
|
+
* incoming: [],
|
|
93
|
+
* outgoing: [{ id: 'edge1', properties: {}, target: 'node2' }]
|
|
94
|
+
* },
|
|
95
|
+
* node2: {
|
|
96
|
+
* id: 'node2',
|
|
97
|
+
* type: 'TaskNode',
|
|
98
|
+
* properties: {},
|
|
99
|
+
* incoming: [{ id: 'edge1', properties: {}, source: 'node1' }],
|
|
100
|
+
* outgoing: [],
|
|
101
|
+
* }
|
|
102
|
+
* }
|
|
103
|
+
* 此格式方便后续执行时,根据节点id快速找到节点和执行初始化节点模型。
|
|
104
|
+
* 同时此方法还会找到所有的开始节点,方便后续执行时,从开始节点开始执行。
|
|
105
|
+
* @param graphData 流程图数据
|
|
106
|
+
*/
|
|
107
|
+
load(graphData: any): void;
|
|
108
|
+
/**
|
|
109
|
+
* 执行流程, 每次执行都会生成一个唯一的executionId,用于区分不同的执行。
|
|
110
|
+
* 同一次执行,这次执行内部的节点执行顺序为并行。内部并行是为了避免异步节点阻塞其他节点的执行。
|
|
111
|
+
* 多次执行,多次执行之间为串行,这里选择串行的原因是避免多次执行之间的数据冲突。
|
|
112
|
+
* example:
|
|
86
113
|
* 一个流程存在着两个开始节点,A和B,A和B的下一个节点都是C,C的下两个节点是D和E。
|
|
87
114
|
* 外部分别触发了A和B的执行,那么A和B的执行是串行的(也就是需要A执行完成后再执行B),但是D和E的执行是并行的。
|
|
88
115
|
* 如果希望A和B的执行是并行的,就不能使用同一个流程模型执行,应该初始化两个。
|
|
116
|
+
* TODO: 去掉此处的对列,直接使用调度器的队列。
|
|
89
117
|
*/
|
|
90
118
|
execute(params: ExecParams): Promise<void>;
|
|
91
119
|
resume(params: ExecParams): Promise<void>;
|
|
92
120
|
/**
|
|
93
|
-
*
|
|
121
|
+
* 创建节点实例, 每个节点实例都会有一个唯一的actionId。
|
|
122
|
+
* 通过executionId、nodeId、actionId可以唯一确定一个节点的某一次执行。
|
|
94
123
|
* @param nodeId 节点Id
|
|
95
124
|
* @returns 节点示例
|
|
96
125
|
*/
|
|
97
|
-
|
|
126
|
+
createAction(nodeId: string): import("./nodes/BaseNode").default;
|
|
98
127
|
/**
|
|
99
128
|
* 更新流程全局数据
|
|
100
129
|
*/
|
|
101
130
|
updateGlobalData(data: any): void;
|
|
102
|
-
|
|
131
|
+
/**
|
|
132
|
+
* 在执行完成后,通知外部此次执行完成。
|
|
133
|
+
* 如果还存在待执行的任务,那么继续执行。
|
|
134
|
+
*/
|
|
135
|
+
private onExecuteFinished;
|
|
136
|
+
/**
|
|
137
|
+
* 从待执行队列中取出需要执行的内容。
|
|
138
|
+
* 会依次判断是否有taskId、nodeId、executionId。
|
|
139
|
+
* 若存在taskId,那么表示恢复执行。
|
|
140
|
+
* 若存在nodeId,那么表示从指定节点开始执行。
|
|
141
|
+
* 若都不存在,那么新建一个executionId,从开始节点开始执行。
|
|
142
|
+
*/
|
|
103
143
|
private createExecution;
|
|
104
144
|
}
|
package/es/FlowModel.js
CHANGED
|
@@ -68,7 +68,7 @@ var FlowModel = /** @class */ (function () {
|
|
|
68
68
|
// 流程包含的节点类型
|
|
69
69
|
this.nodeModelMap = nodeModelMap;
|
|
70
70
|
// 需要执行的队列
|
|
71
|
-
this.
|
|
71
|
+
this.executeList = [];
|
|
72
72
|
// 执行中的任务
|
|
73
73
|
this.executingInstance = null;
|
|
74
74
|
// 外部传入的上下文,最终会传递给每个节点
|
|
@@ -83,18 +83,53 @@ var FlowModel = /** @class */ (function () {
|
|
|
83
83
|
recorder: recorder,
|
|
84
84
|
});
|
|
85
85
|
this.scheduler.on(EVENT_INSTANCE_COMPLETE, function (result) {
|
|
86
|
-
_this.
|
|
86
|
+
_this.onExecuteFinished(result);
|
|
87
87
|
});
|
|
88
88
|
this.scheduler.on(EVENT_INSTANCE_INTERRUPTED, function (result) {
|
|
89
|
-
_this.
|
|
89
|
+
_this.onExecuteFinished(result);
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
FlowModel.prototype.setStartNodeType = function (startNodeType) {
|
|
93
93
|
this.startNodeType = startNodeType;
|
|
94
94
|
};
|
|
95
|
+
/**
|
|
96
|
+
* 解析LogicFlow图数据,将nodes和edges转换成节点格式。
|
|
97
|
+
* 例如:
|
|
98
|
+
* graphData: {
|
|
99
|
+
* nodes: [
|
|
100
|
+
* { id: 'node1', type: 'StartNode', properties: {} },
|
|
101
|
+
* { id: 'node2', type: 'TaskNode', properties: {} },
|
|
102
|
+
* ],
|
|
103
|
+
* edges: [
|
|
104
|
+
* { id: 'edge1', sourceNodeId: 'node1', targetNodeId: 'node2', properties: {} },
|
|
105
|
+
* ]
|
|
106
|
+
* }
|
|
107
|
+
* 转换成:
|
|
108
|
+
* nodeConfigMap: {
|
|
109
|
+
* node1: {
|
|
110
|
+
* id: 'node1',
|
|
111
|
+
* type: 'StartNode',
|
|
112
|
+
* properties: {},
|
|
113
|
+
* incoming: [],
|
|
114
|
+
* outgoing: [{ id: 'edge1', properties: {}, target: 'node2' }]
|
|
115
|
+
* },
|
|
116
|
+
* node2: {
|
|
117
|
+
* id: 'node2',
|
|
118
|
+
* type: 'TaskNode',
|
|
119
|
+
* properties: {},
|
|
120
|
+
* incoming: [{ id: 'edge1', properties: {}, source: 'node1' }],
|
|
121
|
+
* outgoing: [],
|
|
122
|
+
* }
|
|
123
|
+
* }
|
|
124
|
+
* 此格式方便后续执行时,根据节点id快速找到节点和执行初始化节点模型。
|
|
125
|
+
* 同时此方法还会找到所有的开始节点,方便后续执行时,从开始节点开始执行。
|
|
126
|
+
* @param graphData 流程图数据
|
|
127
|
+
*/
|
|
95
128
|
FlowModel.prototype.load = function (graphData) {
|
|
96
129
|
var _this = this;
|
|
97
130
|
var _a = graphData.nodes, nodes = _a === void 0 ? [] : _a, _b = graphData.edges, edges = _b === void 0 ? [] : _b;
|
|
131
|
+
this.startNodes = [];
|
|
132
|
+
this.nodeConfigMap = new Map();
|
|
98
133
|
nodes.forEach(function (node) {
|
|
99
134
|
if (_this.nodeModelMap.has(node.type)) {
|
|
100
135
|
var nodeConfig = {
|
|
@@ -133,24 +168,19 @@ var FlowModel = /** @class */ (function () {
|
|
|
133
168
|
});
|
|
134
169
|
};
|
|
135
170
|
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* 例如:
|
|
171
|
+
* 执行流程, 每次执行都会生成一个唯一的executionId,用于区分不同的执行。
|
|
172
|
+
* 同一次执行,这次执行内部的节点执行顺序为并行。内部并行是为了避免异步节点阻塞其他节点的执行。
|
|
173
|
+
* 多次执行,多次执行之间为串行,这里选择串行的原因是避免多次执行之间的数据冲突。
|
|
174
|
+
* example:
|
|
141
175
|
* 一个流程存在着两个开始节点,A和B,A和B的下一个节点都是C,C的下两个节点是D和E。
|
|
142
176
|
* 外部分别触发了A和B的执行,那么A和B的执行是串行的(也就是需要A执行完成后再执行B),但是D和E的执行是并行的。
|
|
143
177
|
* 如果希望A和B的执行是并行的,就不能使用同一个流程模型执行,应该初始化两个。
|
|
178
|
+
* TODO: 去掉此处的对列,直接使用调度器的队列。
|
|
144
179
|
*/
|
|
145
180
|
FlowModel.prototype.execute = function (params) {
|
|
146
181
|
return __awaiter(this, void 0, void 0, function () {
|
|
147
182
|
return __generator(this, function (_a) {
|
|
148
|
-
this.
|
|
149
|
-
if (this.isRunning) {
|
|
150
|
-
return [2 /*return*/];
|
|
151
|
-
}
|
|
152
|
-
this.isRunning = true;
|
|
153
|
-
this.createExecution();
|
|
183
|
+
this.createExecution(params);
|
|
154
184
|
return [2 /*return*/];
|
|
155
185
|
});
|
|
156
186
|
});
|
|
@@ -158,30 +188,26 @@ var FlowModel = /** @class */ (function () {
|
|
|
158
188
|
FlowModel.prototype.resume = function (params) {
|
|
159
189
|
return __awaiter(this, void 0, void 0, function () {
|
|
160
190
|
return __generator(this, function (_a) {
|
|
161
|
-
this.
|
|
162
|
-
if (this.isRunning) {
|
|
163
|
-
return [2 /*return*/];
|
|
164
|
-
}
|
|
165
|
-
this.isRunning = true;
|
|
166
|
-
this.createExecution();
|
|
191
|
+
this.createExecution(params);
|
|
167
192
|
return [2 /*return*/];
|
|
168
193
|
});
|
|
169
194
|
});
|
|
170
195
|
};
|
|
171
196
|
/**
|
|
172
|
-
*
|
|
197
|
+
* 创建节点实例, 每个节点实例都会有一个唯一的actionId。
|
|
198
|
+
* 通过executionId、nodeId、actionId可以唯一确定一个节点的某一次执行。
|
|
173
199
|
* @param nodeId 节点Id
|
|
174
200
|
* @returns 节点示例
|
|
175
201
|
*/
|
|
176
|
-
FlowModel.prototype.
|
|
202
|
+
FlowModel.prototype.createAction = function (nodeId) {
|
|
177
203
|
var nodeConfig = this.nodeConfigMap.get(nodeId);
|
|
178
204
|
var NodeModel = this.nodeModelMap.get(nodeConfig.type);
|
|
179
|
-
var
|
|
205
|
+
var action = new NodeModel({
|
|
180
206
|
nodeConfig: nodeConfig,
|
|
181
207
|
globalData: this.globalData,
|
|
182
208
|
context: this.context,
|
|
183
209
|
});
|
|
184
|
-
return
|
|
210
|
+
return action;
|
|
185
211
|
};
|
|
186
212
|
/**
|
|
187
213
|
* 更新流程全局数据
|
|
@@ -189,43 +215,40 @@ var FlowModel = /** @class */ (function () {
|
|
|
189
215
|
FlowModel.prototype.updateGlobalData = function (data) {
|
|
190
216
|
this.globalData = __assign(__assign({}, this.globalData), data);
|
|
191
217
|
};
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
var
|
|
198
|
-
if (
|
|
199
|
-
callback
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (this.executeQueue.length > 0) {
|
|
203
|
-
this.createExecution();
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
this.isRunning = false;
|
|
218
|
+
/**
|
|
219
|
+
* 在执行完成后,通知外部此次执行完成。
|
|
220
|
+
* 如果还存在待执行的任务,那么继续执行。
|
|
221
|
+
*/
|
|
222
|
+
FlowModel.prototype.onExecuteFinished = function (result) {
|
|
223
|
+
var index = this.executeList.findIndex(function (i) { return i.executionId === result.executionId; });
|
|
224
|
+
if (index !== -1) {
|
|
225
|
+
var callback = this.executeList[index].callback;
|
|
226
|
+
this.executeList.splice(index, 1);
|
|
227
|
+
callback && callback(result);
|
|
207
228
|
}
|
|
208
229
|
};
|
|
209
|
-
|
|
230
|
+
/**
|
|
231
|
+
* 从待执行队列中取出需要执行的内容。
|
|
232
|
+
* 会依次判断是否有taskId、nodeId、executionId。
|
|
233
|
+
* 若存在taskId,那么表示恢复执行。
|
|
234
|
+
* 若存在nodeId,那么表示从指定节点开始执行。
|
|
235
|
+
* 若都不存在,那么新建一个executionId,从开始节点开始执行。
|
|
236
|
+
*/
|
|
237
|
+
FlowModel.prototype.createExecution = function (execParams) {
|
|
210
238
|
var _this = this;
|
|
211
|
-
|
|
212
|
-
this.executingInstance = execParams;
|
|
213
|
-
if (execParams.executionId) {
|
|
214
|
-
this.executionId = execParams.executionId;
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
this.executionId = createExecId();
|
|
218
|
-
}
|
|
239
|
+
this.executeList.push(execParams);
|
|
219
240
|
// 如果有taskId,那么表示恢复执行
|
|
220
|
-
if (execParams.
|
|
241
|
+
if (execParams.actionId && execParams.executionId && execParams.nodeId) {
|
|
221
242
|
this.scheduler.resume({
|
|
222
|
-
executionId:
|
|
223
|
-
|
|
243
|
+
executionId: execParams.executionId,
|
|
244
|
+
actionId: execParams.actionId,
|
|
224
245
|
nodeId: execParams.nodeId,
|
|
225
246
|
data: execParams.data,
|
|
226
247
|
});
|
|
227
248
|
return;
|
|
228
249
|
}
|
|
250
|
+
var executionId = createExecId();
|
|
251
|
+
execParams.executionId = executionId;
|
|
229
252
|
if (execParams.nodeId) {
|
|
230
253
|
var nodeConfig = this.nodeConfigMap.get(execParams.nodeId);
|
|
231
254
|
if (!nodeConfig) {
|
|
@@ -235,14 +258,13 @@ var FlowModel = /** @class */ (function () {
|
|
|
235
258
|
this.startNodes = [nodeConfig];
|
|
236
259
|
}
|
|
237
260
|
this.startNodes.forEach(function (startNode) {
|
|
238
|
-
_this.scheduler.
|
|
239
|
-
executionId:
|
|
261
|
+
_this.scheduler.addAction({
|
|
262
|
+
executionId: executionId,
|
|
240
263
|
nodeId: startNode.id,
|
|
241
264
|
});
|
|
242
|
-
// 所有的开始节点都执行
|
|
243
265
|
});
|
|
244
266
|
this.scheduler.run({
|
|
245
|
-
executionId:
|
|
267
|
+
executionId: executionId,
|
|
246
268
|
});
|
|
247
269
|
};
|
|
248
270
|
return FlowModel;
|