UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

237 lines • 13.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventHandler = void 0; const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk"); const index_1 = require("../../../Contracts/InternalMessages/index"); const index_2 = require("../../../Tools/index"); const FlowNodeHandler_1 = require("../FlowNodeHandler"); /** * This is the base handler for events. */ class EventHandler extends FlowNodeHandler_1.FlowNodeHandler { triggeredByFlowNodeInstanceId; abortSignal = new AbortController(); async beforeExecute(resolveFunction, rejectFunction) { this.abortSignal.signal.throwIfAborted(); await super.beforeExecute(); this.processEventSubscriptions.push(this.subscribeToProcessKilledEvent(rejectFunction)); this.processEventSubscriptions.push(this.subscribeToTerminateEndEventReached(resolveFunction)); this.processEventSubscriptions.push(this.subscribeToProcessError(rejectFunction)); } async persistOnCancel(typeData) { await super.persistOnCancel(typeData); this.publishIntermediateCatchEventFinishedNotification(); } async execute(previousFlowNodeInstanceId, previousResult, executionCanceledCallback, triggeredByFlowNodeInstanceId) { if (this.processInstance.getState() && this.processInstance.getState() !== processcube_engine_sdk_1.ProcessInstanceState.running) { return undefined; } this.abortSignal.signal.throwIfAborted(); this.triggeredByFlowNodeInstanceId = triggeredByFlowNodeInstanceId; this.previousFlowNodeInstanceId = previousFlowNodeInstanceId; this.processToken = previousResult ?? {}; return new Promise(async (resolve, reject) => { try { await this.beforeExecute(resolve, reject); await this.persistOnEnter(); const nextFlowNodes = await this.startExecution(executionCanceledCallback); await this.persistOnExit(); await this.afterExecute(); if (nextFlowNodes == null || nextFlowNodes.length === 0) { return resolve(); } if (nextFlowNodes.length > 1) { this.throwMultipleSubsequentFlowNodesError(nextFlowNodes); } await this.handleNextFlowNode(nextFlowNodes[0]); return resolve(); } catch (error) { if (this.abortSignal.signal.aborted) { return; } return this.handleError(error, resolve, reject); } }); } async resume(flowNodeInstanceForHandler, allFlowNodeInstances, resumptionCanceledCallback) { this.state = flowNodeInstanceForHandler.state; this.startedAt = flowNodeInstanceForHandler.startedAt; this.abortSignal.signal.throwIfAborted(); return new Promise(async (resolve, reject) => { this.previousFlowNodeInstanceId = flowNodeInstanceForHandler.previousFlowNodeInstanceId; this.flowNodeInstanceId = flowNodeInstanceForHandler.flowNodeInstanceId; try { await this.beforeExecute(resolve, reject); const nextFlowNodes = await this.resumeFromState(flowNodeInstanceForHandler, allFlowNodeInstances, resumptionCanceledCallback); await this.afterExecute(); if (nextFlowNodes == null || nextFlowNodes.length === 0) { return resolve(); } if (nextFlowNodes.length > 1) { this.throwMultipleSubsequentFlowNodesError(nextFlowNodes); } await this.handleNextFlowNode(nextFlowNodes[0], allFlowNodeInstances); return resolve(); } catch (error) { if (this.abortSignal.signal.aborted) { return; } return this.handleError(error, resolve, reject); } }); } async resumeFromState(flowNodeInstance, processFlowNodeInstances, resumptionCanceledCallback) { this.logger.debug(`Resuming FlowNodeInstance.`); let nextFlowNodes = []; switch (flowNodeInstance.state) { case processcube_engine_sdk_1.FlowNodeInstanceState.suspended: this.logger.debug('Event was left suspended. Waiting for the resuming event to happen.'); this.processToken = flowNodeInstance.startToken; nextFlowNodes = await this.resumeAfterSuspend(flowNodeInstance, resumptionCanceledCallback); await this.persistOnExit(); return nextFlowNodes; case processcube_engine_sdk_1.FlowNodeInstanceState.running: this.logger.debug('Event was interrupted at the beginning. Resuming from the start.'); this.processToken = flowNodeInstance.startToken; nextFlowNodes = await this.executeHandler(resumptionCanceledCallback); await this.persistOnExit(); return nextFlowNodes; case processcube_engine_sdk_1.FlowNodeInstanceState.finished: this.logger.debug('Event was already finished. Skipping ahead.'); this.processToken = flowNodeInstance.endToken; return this.processInstance.getProcessModelFacade().getNextFlowNodesFor(this.flowNode); case processcube_engine_sdk_1.FlowNodeInstanceState.error: this.logger.error(`Cannot resume Event, because it previously exited with an error!`, { err: flowNodeInstance.error, processInstanceId: this.processInstance.getProcessInstanceId(), correlationId: this.processInstance.getCorrelationId(), }); // Resetting the state here will cause the error handler to run again, thus triggering and handling all possible boundary events. this.state = processcube_engine_sdk_1.FlowNodeInstanceState.suspended; throw flowNodeInstance.error; case processcube_engine_sdk_1.FlowNodeInstanceState.terminated: const terminatedError = new processcube_engine_sdk_1.InternalServerError(`Cannot resume Event, 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.warn(`Cannot resume Event, because it was canceled.`); return []; default: const invalidStateError = new processcube_engine_sdk_1.InternalServerError(`Cannot resume Event, because its state cannot be determined!`); invalidStateError.additionalInformation = { processInstanceId: this.processInstance.getProcessInstanceId(), correlationId: this.processInstance.getCorrelationId(), }; this.logger.error(invalidStateError.message); throw invalidStateError; } } async passTriggerThroughEventBasedGatwwayIfNecessary() { const processInstanceId = this.processInstance.getProcessInstanceId(); const eventBasedGatewayIocKey = `EventBasedGatewayHandlerInstance-${processInstanceId}-${this.previousFlowNodeInstanceId}`; const isEventBasedGatewayRegistered = this.processInstance.getContainer().isBound(eventBasedGatewayIocKey); if (!isEventBasedGatewayRegistered) { return false; } const eventBasedGateway = this.processInstance.getContainer().get(eventBasedGatewayIocKey); if (eventBasedGateway.hasBeenTriggered) { return true; } const triggerConfirmedByEventBasedGateway = await eventBasedGateway.evaluateAndTriggerCatchEvent(this.flowNodeInstanceId); return !triggerConfirmedByEventBasedGateway; } publishIntermediateThrowEventTriggeredNotification() { 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, flowNodeInstanceId: this.flowNodeInstanceId, processInstanceOwner: this.processInstance.getOwner(), currentToken: this.processToken, previousFlowNodeInstanceId: this.previousFlowNodeInstanceId, eventType: this.flowNode.eventType, eventName: this.getEventName(), }; index_2.EventAggregator.publish(index_1.eventAggregatorSettings.messagePaths.intermediateThrowEventTriggered, message); } publishIntermediateCatchEventReachedNotification() { 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, flowNodeInstanceId: this.flowNodeInstanceId, processInstanceOwner: this.processInstance.getOwner(), currentToken: this.processToken, previousFlowNodeInstanceId: this.previousFlowNodeInstanceId, eventType: this.flowNode.eventType, eventName: this.getEventName(), }; index_2.EventAggregator.publish(index_1.eventAggregatorSettings.messagePaths.intermediateCatchEventReached, message); } publishIntermediateCatchEventFinishedNotification() { 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, flowNodeInstanceId: this.flowNodeInstanceId, processInstanceOwner: this.processInstance.getOwner(), currentToken: this.processToken, previousFlowNodeInstanceId: this.previousFlowNodeInstanceId, eventType: this.flowNode.eventType, eventName: this.getEventName(), flowNodeInstanceState: this.state, }; index_2.EventAggregator.publish(index_1.eventAggregatorSettings.messagePaths.intermediateCatchEventFinished, message); } getEventName() { if (this.flowNode.messageEventDefinition) { return this.flowNode.messageEventDefinition.name; } if (this.flowNode.signalEventDefinition) { return this.flowNode.signalEventDefinition.name; } if (this.flowNode.timerEventDefinition) { return this.flowNode.timerEventDefinition.value; } return undefined; } throwMultipleSubsequentFlowNodesError(nextFlowNodes) { const msg = `Event \`${this.flowNode.id}\` is followed by multiple Flow Nodes. This is not allowed. Events must only be followed by a single Flow Node.`; const multipleOutgoingFlowsError = new processcube_engine_sdk_1.BadRequestError(msg, 'process'); multipleOutgoingFlowsError.additionalInformation = { nextFlowNodes: nextFlowNodes.map((nextFlowNode) => { return { flowNodeId: nextFlowNode.id, connectingSequenceFlowId: this.processInstance.getProcessModelFacade().getSequenceFlowBetween(this.flowNode, nextFlowNode), }; }), }; throw multipleOutgoingFlowsError; } } exports.EventHandler = EventHandler; //# sourceMappingURL=EventHandler.js.map