@logicflow/engine
Version:
a process engine for javascript
179 lines • 7.21 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Scheduler = void 0;
const tslib_1 = require("tslib");
const EventEmitter_1 = tslib_1.__importDefault(require("./EventEmitter"));
const utils_1 = require("./utils");
const constant_1 = require("./constant");
/**
* 调度器
* 通过一个队列维护需要执行的节点,一个集合维护正在执行的节点
*/
class Scheduler extends EventEmitter_1.default {
constructor(config) {
super();
this.nodeQueueMap = new Map();
this.actionRunningMap = new Map();
this.flowModel = config.flowModel;
this.recorder = config.recorder;
}
/**
* 添加一个任务到队列中。
* 1. 由流程模型将所有的开始及诶带你添加到队列中
* 2. 当一个节点执行完成后,将后续的节点添加到队列中
* @param nodeParam
*/
addAction(nodeParam) {
const { executionId } = nodeParam;
if (!this.nodeQueueMap.has(executionId)) {
this.nodeQueueMap.set(executionId, []);
}
const currentActionQueue = this.nodeQueueMap.get(executionId);
if (currentActionQueue) {
currentActionQueue.push(nodeParam);
}
console.log('this.nodeQueueMap--->>>', this.nodeQueueMap);
}
pushActionToRunningMap(actionParam) {
var _a;
const { executionId, actionId } = actionParam;
if (!this.actionRunningMap.has(executionId)) {
const runningMap = new Map();
this.actionRunningMap.set(executionId, runningMap);
}
if (actionId) {
(_a = this.actionRunningMap.get(executionId)) === null || _a === void 0 ? void 0 : _a.set(actionId, actionParam);
}
}
removeActionFromRunningMap(actionParam) {
const { executionId, actionId } = actionParam;
if (!actionId)
return;
const runningMap = this.actionRunningMap.get(executionId);
if (!runningMap)
return;
runningMap.delete(actionId);
}
/**
* 为了防止多次添加导致
* @param actionParam
*/
saveActionResult(actionParam) {
var _a;
(_a = this.recorder) === null || _a === void 0 ? void 0 : _a.addActionRecord(Object.assign({ timestamp: Date.now() }, actionParam));
}
hasRunningAction(executionId) {
const runningMap = this.actionRunningMap.get(executionId);
if (!runningMap)
return false;
if (runningMap.size === 0) {
this.actionRunningMap.delete(executionId);
return false;
}
return true;
}
/**
* 调度器执行下一个任务
* 1. 提供给流程模型,用户开始执行第一个任务
* 2. 内部任务执行完成后,调用此方法继续执行下一个任务
* 3. 当判断没有可以继续执行的任务后,触发流程结束事件
* @param runParam
*/
run(runParam) {
const nodeQueue = this.nodeQueueMap.get(runParam.executionId);
// 将同一个 executionId 当前待执行的节点一起执行
// 避免出现某一个节点执行时间过长,导致其他节点等待时间过长
while (nodeQueue === null || nodeQueue === void 0 ? void 0 : nodeQueue.length) {
const currentNode = nodeQueue.pop();
const actionId = (0, utils_1.createActionId)();
const actionParam = Object.assign(Object.assign({}, currentNode), { actionId });
this.pushActionToRunningMap(actionParam);
this.exec(actionParam);
}
if (!this.hasRunningAction(runParam.executionId)) {
// 当一个流程在 nodeQueueMap 和 actionRunningMap 中都不存在执行的节点时,说明这个流程已经执行完成。
this.emit(constant_1.EVENT_INSTANCE_COMPLETE, Object.assign(Object.assign({}, runParam), { status: constant_1.FlowStatus.COMPLETED }));
}
}
next(data) {
if (data.outgoing && data.outgoing.length > 0) {
data.outgoing.forEach((item) => {
if (item.result) {
this.addAction({
executionId: data.executionId,
nodeId: item.target,
});
}
});
}
this.saveActionResult(data);
this.removeActionFromRunningMap(data);
this.run(data);
}
/**
* 恢复某个任务的执行
* 可以自定义节点手动实现流程中断,然后通过此方法恢复流程的执行
* @param resumeParam
*/
resume(resumeParam) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const { executionId, actionId, nodeId } = resumeParam;
this.pushActionToRunningMap({
executionId,
actionId,
nodeId,
});
const model = this.flowModel.createAction(nodeId);
yield (model === null || model === void 0 ? void 0 : model.resume(Object.assign(Object.assign({}, resumeParam), { next: this.next.bind(this) })));
});
}
// 中断时,触发事件
interrupted(execResult) {
this.emit(constant_1.EVENT_INSTANCE_INTERRUPTED, execResult);
}
// 报错时,触发事件
error(execResult) {
this.emit(constant_1.EVENT_INSTANCE_ERROR, execResult);
}
exec(actionParam) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const { executionId, actionId, nodeId } = actionParam;
const model = this.flowModel.createAction(nodeId);
const execResult = yield (model === null || model === void 0 ? void 0 : model.execute({
executionId,
actionId,
nodeId,
next: this.next.bind(this),
}));
if (execResult) {
const { nodeType, properties, outgoing, status, detail } = execResult;
const actionResult = {
// actionParam
executionId,
actionId,
nodeId,
// execResult
nodeType,
properties,
outgoing,
status,
detail,
};
if ((execResult === null || execResult === void 0 ? void 0 : execResult.status) === constant_1.FlowStatus.INTERRUPTED) {
this.interrupted(execResult);
this.saveActionResult(actionResult);
this.removeActionFromRunningMap(actionParam);
}
if ((execResult === null || execResult === void 0 ? void 0 : execResult.status) === constant_1.FlowStatus.ERROR) {
this.error(execResult);
this.saveActionResult(actionResult);
this.removeActionFromRunningMap(actionParam);
}
}
// TODO: 考虑停下所有的任务
});
}
}
exports.Scheduler = Scheduler;
exports.default = Scheduler;
//# sourceMappingURL=Scheduler.js.map