UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

154 lines 9.03 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.ParallelJoinGatewayHandler = void 0; const inversify_1 = require("inversify"); const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk"); const index_1 = require("../../../Tools/DatabaseAdaptersSequelize/index"); const EventAggregator_1 = __importDefault(require("../../../Tools/EventAggregator")); const EventMiddlewareHandler_1 = require("../../../Tools/EventMiddlewareHandler"); const ProcessInstance_1 = require("../../ProcessInstance"); const FlowNodeHandlerFactory_1 = require("../FlowNodeHandlerFactory"); const GatewayHandler_1 = require("./GatewayHandler"); let ParallelJoinGatewayHandler = class ParallelJoinGatewayHandler extends GatewayHandler_1.GatewayHandler { isInterrupted = false; constructor(eventMiddlewareHandler, flowNodeHandlerFactory, flowNodeInstanceDatabaseAdapter, parallelGatewayModel, processInstance) { super(eventMiddlewareHandler, flowNodeHandlerFactory, flowNodeInstanceDatabaseAdapter, parallelGatewayModel, processInstance, 'parallel_join_gateway'); } get parallelGateway() { return this.flowNode; } async beforeExecute(resolveFunction, rejectFunction, resumedFlowNodeInstances) { // Safety check to prevent a handler to be resolved and called after it was already finished. if (this.isInterrupted) { return; } if (this.processEventSubscriptions.length == 0) { this.processEventSubscriptions.push(this.subscribeToProcessKilledEvent(rejectFunction)); this.processEventSubscriptions.push(this.subscribeToTerminateEndEventReached(resolveFunction)); this.processEventSubscriptions.push(this.subscribeToProcessError(rejectFunction)); } if (resumedFlowNodeInstances) { const previousFlowNodeInstanceIds = this.previousFlowNodeInstanceId.split(';'); const unaccountedFlowNodeInstances = resumedFlowNodeInstances.filter((flowNodeInstance) => { return previousFlowNodeInstanceIds.includes(flowNodeInstance.flowNodeInstanceId) && !this.flowNodeInstancesArrivedAtGateway.includes(flowNodeInstance.flowNodeInstanceId); }); const newFlowNodeInstanceIds = unaccountedFlowNodeInstances.map((flowNodeInstance) => flowNodeInstance.flowNodeInstanceId); this.flowNodeInstancesArrivedAtGateway.push(...newFlowNodeInstanceIds); } else { this.flowNodeInstancesArrivedAtGateway.push(...this.previousFlowNodeInstanceId.split(';')); } } async afterExecute() { this.publishGatewayFinishedNotification(); } // This gateway can only resume, after all incoming paths have arrived. // But since a single execution thread can end after arriving at the gateway, we need to override this hook, in order to prevent an early state transition. async persistOnExit() { } async startExecution() { if (this.isInterrupted) { return undefined; } this.logger.debug(`Executing ParallelJoinGateway instance.`); await this.persistOnEnter(this.flowNodeInstancesArrivedAtGateway); return this.executeHandler(); } async executeHandler() { const previousFlowNodes = this.processInstance.getProcessModelFacade().getPreviousFlowNodesFor(this.parallelGateway); const flowNodeInstanceQueryResult = await this.flowNodeInstanceAdapter.query({ flowNodeInstanceId: this.flowNodeInstancesArrivedAtGateway, }); const previousFlowNodeInstances = flowNodeInstanceQueryResult.flowNodeInstances; const notAllBranchesHaveFinished = !previousFlowNodes.every((previousFlowNode) => { return previousFlowNodeInstances.some((result) => result.flowNodeId === previousFlowNode.id); }); if (notAllBranchesHaveFinished) { this.logger.trace('Not all branches have finished.', { previousFlowNodes: previousFlowNodes, previousFlowNodeInstances: previousFlowNodeInstances, flowNodeInstancesArrivedAtGateway: this.flowNodeInstancesArrivedAtGateway, }); return undefined; } this.cleanupSubscriptions(); await this.removeInstanceFromIocContainer(); this.processToken = this.aggregateResults(previousFlowNodeInstances); await super.persistOnExit(); return this.processInstance.getProcessModelFacade().getNextFlowNodesFor(this.parallelGateway); } aggregateResults(incomingFlowNodeInstances) { const resultToken = {}; for (const incomingFlowNodeInstanceId of this.flowNodeInstancesArrivedAtGateway) { const incomingFlowNodeInstance = incomingFlowNodeInstances.find((flowNodeInstance) => flowNodeInstance.flowNodeInstanceId === incomingFlowNodeInstanceId); resultToken[incomingFlowNodeInstance.flowNodeId] = incomingFlowNodeInstance.endToken ?? {}; } return resultToken; } subscribeToProcessKilledEvent(rejectionFunction) { return this.processInstance.onKillProcess(async (message) => { // This is done to prevent anybody from accessing the handler after a kill message was received. this.isInterrupted = true; this.cleanupSubscriptions(); await this.persistOnTerminate(); await this.removeInstanceFromIocContainer(); return rejectionFunction(); }); } subscribeToProcessError(rejectionFunction) { return this.processInstance.onProcessError(async (message) => { // This is done to prevent anybody from accessing the handler after an error message was received. this.isInterrupted = true; this.cleanupSubscriptions(); const payloadIsDefined = message != undefined; this.processToken = payloadIsDefined ? message.currentToken : {}; const error = new processcube_engine_sdk_1.InternalServerError('ProcessInstance encountered an error!'); error.additionalInformation = message.currentToken; await this.removeInstanceFromIocContainer(); await this.onInterruptedCallback(this.processToken); await this.persistOnError(error); return rejectionFunction(); }); } subscribeToTerminateEndEventReached(resolveFunction) { return this.processInstance.onTerminateEndEventReached(async (message) => { // This is done to prevent anybody from accessing the handler after the process is stopped by a terminate end event. this.isInterrupted = true; this.cleanupSubscriptions(); await this.removeInstanceFromIocContainer(); this.processToken = {}; this.logger.debug('Cancelling Flow Node Execution, because a Terminate End Event has been reached.'); await this.cancel(this.processToken); return resolveFunction(); }); } cleanupSubscriptions() { this.processEventSubscriptions.forEach((subscription) => EventAggregator_1.default.unsubscribe(subscription)); } async removeInstanceFromIocContainer() { const processInstanceId = this.processInstance.getProcessInstanceId(); const joinGatewayRegistration = `ParallelJoinGatewayHandlerInstance-${processInstanceId}-${this.parallelGateway.id}`; if (this.processInstance.getContainer().isBound(joinGatewayRegistration)) { await this.processInstance.getContainer().unbind(joinGatewayRegistration); } } }; exports.ParallelJoinGatewayHandler = ParallelJoinGatewayHandler; exports.ParallelJoinGatewayHandler = ParallelJoinGatewayHandler = __decorate([ (0, inversify_1.injectable)(), __metadata("design:paramtypes", [EventMiddlewareHandler_1.EventMiddlewareHandler, FlowNodeHandlerFactory_1.FlowNodeHandlerFactory, index_1.FlowNodeInstanceDatabaseAdapter, Object, ProcessInstance_1.ProcessInstance]) ], ParallelJoinGatewayHandler); //# sourceMappingURL=ParallelJoinGatewayHandler.js.map