@5minds/processcube_engine
Version:
The ProcessCube Engine. Stores and executes BPMNs.
237 lines • 13.2 kB
JavaScript
"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