UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

242 lines • 14.1 kB
"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