@5minds/processcube_engine
Version:
The ProcessCube Engine. Stores and executes BPMNs.
242 lines • 14.1 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TimerBoundaryEventHandler = void 0;
const dayjs_1 = __importDefault(require("dayjs"));
const inversify_1 = require("inversify");
const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk");
const index_1 = require("../../../Contracts/index");
const Tools_1 = require("../../../Tools");
const index_2 = require("../../../Tools/DatabaseAdaptersSequelize/index");
const EventMiddlewareHandler_1 = require("../../../Tools/EventMiddlewareHandler");
const TimerFacade_1 = require("../../Facades/TimerFacade");
const ProcessInstance_1 = require("../../ProcessInstance");
const FlowNodeHandlerFactory_1 = require("../FlowNodeHandlerFactory");
const BoundaryEventHandler_1 = require("./BoundaryEventHandler");
let TimerBoundaryEventHandler = class TimerBoundaryEventHandler extends BoundaryEventHandler_1.BoundaryEventHandler {
timerFacade;
timerSubscription;
constructor(eventMiddlewareHandler, flowNodeInstanceDatabaseAdapter, flowNodeHandlerFactory, timerFacade, boundaryEventModel, processInstance, processTokenOfAttachedFlowNode) {
super(eventMiddlewareHandler, flowNodeInstanceDatabaseAdapter, flowNodeHandlerFactory, boundaryEventModel, processInstance, processTokenOfAttachedFlowNode, 'timer_boundary_event_handler');
this.timerFacade = timerFacade;
}
async execute(onTriggeredCallback, attachedFlowNodeInstanceId, decoratedFlowNodeRejectFunc) {
try {
this.logger.debug(`Initializing Timer BoundaryEvent on FlowNodeInstance ${attachedFlowNodeInstanceId}`);
const timerExpression = await this.parseTimerValue();
let stringifiedTimerExpression;
if (typeof timerExpression?.toISOString === 'function') {
stringifiedTimerExpression = timerExpression.toISOString();
}
else if (typeof timerExpression != 'string') {
stringifiedTimerExpression = JSON.stringify(timerExpression);
}
else {
stringifiedTimerExpression = timerExpression;
}
const typeSpecificData = {
type: index_1.FlowNodeInstanceDataTypes.catchEvent,
eventName: stringifiedTimerExpression,
};
await this.initialize(attachedFlowNodeInstanceId, undefined, typeSpecificData);
this.validateTimer();
await this.executeTimer(onTriggeredCallback, timerExpression);
return this.handleNextFlowNodes();
}
catch (error) {
if (this.executionPromise?.controller.signal.aborted) {
return;
}
// persistOnError would fail, if the Boundary>Event Instance was not previously persisted.
// This can happen, if running the timer expression fails.
// Running "persistOnEnter" again is actually safe, because a repeated call doesn't do anything.
await this.persistOnEnter();
await this.persistOnError(error);
decoratedFlowNodeRejectFunc(error);
return;
}
}
async resume(boundaryEventInstance, onTriggeredCallback, attachedFlowNodeInstanceId, decoratedFlowNodeRejectFunc, flowNodeInstances) {
this.boundaryEventInstance = boundaryEventInstance;
this.eventWasTriggered = this.boundaryEventWasTriggered(flowNodeInstances);
if (this.eventWasTriggered) {
return this.handleNextFlowNodes(flowNodeInstances);
}
try {
await this.initialize(attachedFlowNodeInstanceId, boundaryEventInstance);
if (this.boundaryEventInstance?.state === processcube_engine_sdk_1.FlowNodeInstanceState.canceled) {
return;
}
const timerStartedDate = boundaryEventInstance.startedAt;
const timerExpression = boundaryEventInstance.eventName || (await this.parseTimerValue());
this.logger.debug(`Resuming BoundaryEvent on FlowNodeInstance ${attachedFlowNodeInstanceId}`);
await this.executeTimer(onTriggeredCallback, timerExpression, timerStartedDate);
}
catch (error) {
if (this.executionPromise.controller.signal.aborted) {
return;
}
await this.persistOnError(error);
decoratedFlowNodeRejectFunc(error);
return;
}
return this.handleNextFlowNodes();
}
async finish() {
await this.removeTimer();
await super.finish();
}
async cancel() {
await this.removeTimer();
if (!this.boundaryEventModel.cancelActivity && this.eventWasTriggered) {
this.executionFinishCallback?.();
}
await super.cancel();
}
validateTimer() {
if (!this.boundaryEventModel.timerEventDefinition.timerType || !this.boundaryEventModel.timerEventDefinition.value) {
const errorToThrow = new processcube_engine_sdk_1.BadRequestError('Timer Boundary Event does not have a type or definition assigned.', 'process');
errorToThrow.additionalInformation = {
flowNodeInstanceId: this.boundaryEventInstanceId,
flowNodeId: this.boundaryEventModel.id,
flowNodeName: this.boundaryEventModel.name,
processInstanceId: this.processInstance.getProcessInstanceId(),
processModelId: this.processInstance.getProcessModelId(),
embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(),
correlationId: this.processInstance.getCorrelationId(),
};
throw errorToThrow;
}
}
async executeTimer(onTriggeredCallback, timerExpression, timerStartedDate) {
this.createExecutionPromise(async (resolve) => {
if (!this.boundaryEventModel.cancelActivity) {
this.executionFinishCallback = resolve;
}
const timerElapsed = async () => {
if (this.eventWasTriggered || this.state !== processcube_engine_sdk_1.FlowNodeInstanceState.running) {
return;
}
this.eventWasTriggered = true;
const processModelId = this.processInstance.getProcessModelId();
this.logger.debug(`TimerBoundaryEvent for ProcessModel ${processModelId} was triggered.`);
const nextFlowNode = this.getNextFlowNode();
await this.runPostScript();
const isInterruptingOrDateOrDurationEvent = this.boundaryEventModel.cancelActivity ||
[processcube_engine_sdk_1.Model.Events.TimerType.timeDate, processcube_engine_sdk_1.Model.Events.TimerType.timeDuration].includes(this.boundaryEventModel.timerEventDefinition.timerType);
const eventData = {
boundaryInstanceId: this.boundaryEventInstanceId,
nextFlowNode: nextFlowNode,
interruptHandler: this.boundaryEventModel.cancelActivity,
eventPayload: this.processToken,
canTriggerMultipleTimes: !isInterruptingOrDateOrDurationEvent,
};
await this.saveTokenInDataObjects(eventData.eventPayload, this.boundaryEventModel.id);
this.sendBoundaryEventTriggeredNotification(this.boundaryEventModel.timerEventDefinition.value);
onTriggeredCallback(eventData);
resolve();
};
this.timerSubscription = this.timerFacade.initializeTimer(this.boundaryEventModel.id, this.boundaryEventModel.timerEventDefinition.timerType, timerExpression, timerElapsed, this.boundaryEventModel, timerStartedDate);
const triggerTimerImmediatelyEvent = index_1.eventAggregatorSettings.messagePaths.triggerTimerEvent.replace(index_1.eventAggregatorSettings.messageParams.flowNodeInstanceId, this.boundaryEventInstanceId);
Tools_1.EventAggregator.subscribeOnce(triggerTimerImmediatelyEvent, () => {
this.timerFacade.triggerTimerImmediately(this.timerSubscription, this.boundaryEventModel.timerEventDefinition.timerType);
});
});
await this.postEventToEventMiddlewares({
correlationId: this.processInstance.getCorrelationId(),
processModelId: this.processInstance.getProcessModelId(),
embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(),
processModelName: this.processInstance.getProcessModelName(),
processInstanceId: this.processInstance.getProcessInstanceId(),
parentProcessInstanceId: this.processInstance.getParentProcessInstance()?.getProcessInstanceId(),
processDefinitionId: this.processInstance.getProcessDefinitionId(),
processDefinitionHash: this.processInstance.getProcessDefinitionHash(),
flowNodeId: this.boundaryEventModel.id,
flowNodeName: this.boundaryEventModel.name,
flowNodeType: this.boundaryEventModel.bpmnType,
flowNodeLane: this.processInstance.getProcessModelFacade().getLaneForFlowNode(this.boundaryEventModel.id)?.name,
flowNodeInstanceId: this.boundaryEventInstanceId,
logLevel: processcube_engine_sdk_1.LogLevel.debug,
eventType: processcube_engine_sdk_1.EngineEventType.OnFlowNodeTimerStarted,
tokenPayload: this.processToken,
timestamp: dayjs_1.default.utc().toDate(),
});
return this.executionPromise.promise;
}
async parseTimerValue() {
const timerExpression = this.boundaryEventModel.timerEventDefinition.value;
const isConstantTimerExpression = !timerExpression ||
!this.processInstance
.getProcessTokenService()
.getAvailableParametersForExpressions()
.some((param) => timerExpression.includes(param));
if (isConstantTimerExpression) {
return timerExpression;
}
try {
return this.processInstance.executeRuntimeExpression({
expression: timerExpression,
currentFlowNode: this.boundaryEventModel,
currentToken: this.processToken,
previousFlowNode: this.processInstance.getProcessModelFacade().getPreviousFlowNodesFor(this.boundaryEventModel)?.pop(),
allowNonObjectResults: true,
});
}
catch (err) {
this.logger.error(err);
err.additionalInformation = {
flowNodeInstanceId: this.boundaryEventInstanceId,
flowNodeType: this.boundaryEventModel.bpmnType,
flowNodeId: this.boundaryEventModel.id,
processModelId: this.processInstance.getProcessModelId(),
embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(),
processInstanceId: this.processInstance.getProcessInstanceId(),
correlationId: this.processInstance.getCorrelationId(),
};
throw err;
}
}
async removeTimer() {
this.logger.trace('Disposing Timer');
this.timerFacade.cancelTimerSubscription(this.timerSubscription);
await this.postEventToEventMiddlewares({
correlationId: this.processInstance.getCorrelationId(),
processModelId: this.processInstance.getProcessModelId(),
embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(),
processModelName: this.processInstance.getProcessModelName(),
processInstanceId: this.processInstance.getProcessInstanceId(),
parentProcessInstanceId: this.processInstance.getParentProcessInstance()?.getProcessInstanceId(),
processDefinitionId: this.processInstance.getProcessDefinitionId(),
processDefinitionHash: this.processInstance.getProcessDefinitionHash(),
flowNodeId: this.boundaryEventModel.id,
flowNodeName: this.boundaryEventModel.name,
flowNodeType: this.boundaryEventModel.bpmnType,
flowNodeLane: this.processInstance.getProcessModelFacade().getLaneForFlowNode(this.boundaryEventModel.id)?.name,
flowNodeInstanceId: this.boundaryEventInstanceId,
logLevel: processcube_engine_sdk_1.LogLevel.debug,
eventType: processcube_engine_sdk_1.EngineEventType.OnFlowNodeTimerRemoved,
tokenPayload: this.processToken,
timestamp: dayjs_1.default.utc().toDate(),
});
}
};
exports.TimerBoundaryEventHandler = TimerBoundaryEventHandler;
exports.TimerBoundaryEventHandler = TimerBoundaryEventHandler = __decorate([
(0, inversify_1.injectable)(),
__metadata("design:paramtypes", [EventMiddlewareHandler_1.EventMiddlewareHandler,
index_2.FlowNodeInstanceDatabaseAdapter,
FlowNodeHandlerFactory_1.FlowNodeHandlerFactory,
TimerFacade_1.TimerFacade, Object, ProcessInstance_1.ProcessInstance, Object])
], TimerBoundaryEventHandler);
//# sourceMappingURL=TimerBoundaryEventHandler.js.map