UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

193 lines • 10.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GatewayHandler = void 0; const async_lock_1 = __importDefault(require("async-lock")); const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk"); const Contracts_1 = require("../../../Contracts"); const EventAggregator_1 = __importDefault(require("../../../Tools/EventAggregator")); const FlowNodeHandler_1 = require("../FlowNodeHandler"); const lock = new async_lock_1.default(); class GatewayHandler extends FlowNodeHandler_1.FlowNodeHandler { flowNodeInstancesArrivedAtGateway = []; unresolved = []; async beforeExecute(resolveFunction, rejectFunction, resumedFlowNodeInstances) { await super.beforeExecute(); this.processEventSubscriptions.push(this.subscribeToProcessKilledEvent(rejectFunction)); this.processEventSubscriptions.push(this.subscribeToTerminateEndEventReached(resolveFunction)); this.processEventSubscriptions.push(this.subscribeToProcessError(rejectFunction)); } async afterExecute() { await super.afterExecute(); this.publishGatewayFinishedNotification(); } async execute(previousFlowNodeInstanceId, previousResult) { const processInstanceState = this.processInstance.getState(); if (processInstanceState && processInstanceState !== processcube_engine_sdk_1.ProcessInstanceState.running) { return undefined; } return new Promise(async (resolve, reject) => { try { let nextFlowNodes; await lock.acquire(this.flowNodeInstanceId, async () => { if (this.state === processcube_engine_sdk_1.FlowNodeInstanceState.finished) { return resolve(); } this.previousFlowNodeInstanceId = previousFlowNodeInstanceId; this.processToken = previousResult ?? {}; await this.beforeExecute(resolve, reject); await this.persistOnEnter(this.flowNodeInstancesArrivedAtGateway); this.publishGatewayReachedNotification(); const gatewayTypeIsNotSupported = this.flowNode.gatewayDirection === processcube_engine_sdk_1.Model.Gateways.GatewayDirection.Unspecified || this.flowNode.gatewayDirection === processcube_engine_sdk_1.Model.Gateways.GatewayDirection.Mixed; if (gatewayTypeIsNotSupported) { const unsupportedErrorMessage = `Gateway ${this.flowNode.id} is not connected correctly.\n` + 'Only Split Gateways (one incoming and multiple outgoing Sequence Flows) and ' + 'Join Gateways (multiple incoming and one outgoing Sequence Flow) are supported.'; this.logger.error(unsupportedErrorMessage); const errorToThrow = new processcube_engine_sdk_1.UnprocessableEntityError(unsupportedErrorMessage, 'process'); throw errorToThrow; } nextFlowNodes = await this.startExecution(); await this.persistOnExit(); await this.afterExecute(); }); if (nextFlowNodes == null || nextFlowNodes.length === 0) { this.unresolved.push(resolve); return; } const nextFlowNodeExecutionPromises = []; for (const nextFlowNode of nextFlowNodes) { const handleNextFlowNodePromise = this.handleNextFlowNode(nextFlowNode); nextFlowNodeExecutionPromises.push(handleNextFlowNodePromise); } await Promise.all(nextFlowNodeExecutionPromises); this.unresolved.forEach((r) => r()); return resolve(); } catch (error) { return this.handleError(error, resolve, reject); } }); } async resume(flowNodeInstanceForHandler, allFlowNodeInstances) { this.state = flowNodeInstanceForHandler.state; this.startedAt = flowNodeInstanceForHandler.startedAt; return new Promise(async (resolve, reject) => { try { let nextFlowNodes; await lock.acquire(this.flowNodeInstanceId, async () => { this.previousFlowNodeInstanceId = flowNodeInstanceForHandler.previousFlowNodeInstanceId; this.flowNodeInstanceId = flowNodeInstanceForHandler.flowNodeInstanceId; await this.beforeExecute(resolve, reject, allFlowNodeInstances); this.publishGatewayReachedNotification(); nextFlowNodes = await this.resumeFromState(flowNodeInstanceForHandler, allFlowNodeInstances); await this.afterExecute(); }); if (nextFlowNodes == null || nextFlowNodes.length === 0) { return resolve(); } const nextFlowNodeExecutionPromises = []; for (const nextFlowNode of nextFlowNodes) { const handleNextFlowNodePromise = this.handleNextFlowNode(nextFlowNode, allFlowNodeInstances); nextFlowNodeExecutionPromises.push(handleNextFlowNodePromise); } await Promise.all(nextFlowNodeExecutionPromises); return resolve(); } catch (error) { return this.handleError(error, resolve, reject); } }); } async resumeFromState(flowNodeInstance, processFlowNodeInstances) { this.logger.debug(`Resuming FlowNodeInstance.`); switch (flowNodeInstance.state) { case processcube_engine_sdk_1.FlowNodeInstanceState.running: this.logger.debug('Resuming Gateway.'); this.processToken = flowNodeInstance.startToken; const nextFlowNodes = await this.executeHandler(); await this.persistOnExit(); return nextFlowNodes; case processcube_engine_sdk_1.FlowNodeInstanceState.finished: this.logger.debug('Gateway was already finished. Skipping ahead.'); this.processToken = flowNodeInstance.endToken; return this.resumeAfterExit(processFlowNodeInstances); case processcube_engine_sdk_1.FlowNodeInstanceState.error: this.logger.error(`Cannot resume Gateway, because it previously exited with an error!`, { err: flowNodeInstance.error, }); throw flowNodeInstance.error; case processcube_engine_sdk_1.FlowNodeInstanceState.terminated: const terminatedError = new processcube_engine_sdk_1.InternalServerError(`Cannot resume Gateway, because it was terminated!`); terminatedError.additionalInformation = { processInstanceId: this.processInstance.getProcessInstanceId(), correlationId: this.processInstance.getCorrelationId(), }; this.logger.error(terminatedError.message); throw terminatedError; case processcube_engine_sdk_1.FlowNodeInstanceState.canceled: this.logger.debug(`Cannot resume Gateway, because it was canceled.`); return []; default: const invalidStateError = new processcube_engine_sdk_1.InternalServerError(`Cannot resume Gateway, because its state cannot be determined!`); invalidStateError.additionalInformation = { processInstanceId: this.processInstance.getProcessInstanceId(), correlationId: this.processInstance.getCorrelationId(), }; this.logger.error(invalidStateError.message); throw invalidStateError; } } async resumeAfterExit(allFlowNodeInstances) { return this.processInstance.getProcessModelFacade().getNextFlowNodesFor(this.flowNode); } async persistOnTerminate(typeData) { this.unresolved.forEach((r) => r()); await super.persistOnTerminate(typeData); } async persistOnError(error, typeData) { this.unresolved.forEach((r) => r()); await super.persistOnError(error, typeData); } publishGatewayReachedNotification() { const message = { correlationId: this.processInstance.getCorrelationId(), processDefinitionId: this.processInstance.getProcessDefinitionId(), processModelId: this.processInstance.getProcessModelId(), processModelName: this.processInstance.getProcessModelName(), processInstanceId: this.processInstance.getProcessInstanceId(), parentProcessInstanceId: this.processInstance.getParentProcessInstance()?.getProcessInstanceId(), flowNodeId: this.flowNode.id, flowNodeName: this.flowNode.name, flowNodeType: this.flowNode.bpmnType, flowNodeInstanceId: this.flowNodeInstanceId, processInstanceOwner: this.processInstance.getOwner(), currentToken: this.processToken, previousFlowNodeInstanceId: this.previousFlowNodeInstanceId, }; EventAggregator_1.default.publish(Contracts_1.eventAggregatorSettings.messagePaths.gatewayReached, message); } publishGatewayFinishedNotification() { const message = { correlationId: this.processInstance.getCorrelationId(), processDefinitionId: this.processInstance.getProcessDefinitionId(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), processModelName: this.processInstance.getProcessModelName(), processInstanceId: this.processInstance.getProcessInstanceId(), parentProcessInstanceId: this.processInstance.getParentProcessInstance()?.getProcessInstanceId(), flowNodeId: this.flowNode.id, flowNodeName: this.flowNode.name, flowNodeType: this.flowNode.bpmnType, flowNodeInstanceId: this.flowNodeInstanceId, processInstanceOwner: this.processInstance.getOwner(), currentToken: this.processToken, previousFlowNodeInstanceId: this.previousFlowNodeInstanceId, }; EventAggregator_1.default.publish(Contracts_1.eventAggregatorSettings.messagePaths.gatewayFinished, message); } } exports.GatewayHandler = GatewayHandler; //# sourceMappingURL=GatewayHandler.js.map