UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

315 lines • 14.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); 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 __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExternalTaskDatabaseAdapter = void 0; const inversify_1 = require("inversify"); const sequelize_1 = require("sequelize"); const uuid = __importStar(require("uuid")); const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk"); const index_1 = require("../../Contracts/InternalMessages/index"); const EventAggregator_1 = __importDefault(require("../EventAggregator")); const BaseDatabaseAdapter_1 = require("./BaseDatabaseAdapter"); const Compression_1 = require("./Lib/Compression"); const SearchQueryBuilder_1 = require("./Lib/SearchQueryBuilder"); const SequelizeConnectionManager_1 = require("./Lib/SequelizeConnectionManager"); const index_2 = require("./Models/index"); let ExternalTaskDatabaseAdapter = class ExternalTaskDatabaseAdapter extends BaseDatabaseAdapter_1.DatabaseAdapter { async initialize() { await super.initialize('database_adapter:external_tasks'); } // Only used by the External Service Task Handler async findByFlowNodeInstanceId(flowNodeInstanceId) { const request = { where: { flowNodeInstanceId: flowNodeInstanceId }, include: this.getJoinsForSelectQuery(), }; const result = await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => index_2.ExternalTaskModel.findOne(request), `find ExternalTask by flowNodeInstanceId '${flowNodeInstanceId}'`); if (!result) { return undefined; } const externalTask = await this.convertToRuntimeObject(result); return externalTask; } // Only used by the API's External Task Service async findByExternalTaskId(externalTaskId) { const request = { where: { externalTaskId: externalTaskId }, include: this.getJoinsForSelectQuery(), }; const result = await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => index_2.ExternalTaskModel.findOne(request), `find ExternalTask by externalTaskId '${externalTaskId}'`); if (!result) { throw new processcube_engine_sdk_1.NotFoundError(`External Task with ID \`${externalTaskId}\` not found.`); } const externalTask = await this.convertToRuntimeObject(result); return externalTask; } async ensureExternalTaskForFlowNodeInstanceIdIsCreated(data) { return await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => { let externalTask = await index_2.ExternalTaskModel.findOne({ where: { flowNodeInstanceId: data.flowNodeInstanceId, }, include: this.getJoinsForSelectQuery(), }); if (!externalTask) { await index_2.ExternalTaskModel.create({ flowNodeInstanceId: data.flowNodeInstanceId, externalTaskId: data.externalTaskId ?? uuid.v4(), topic: data.topic, isSingleTry: data.isSingleTry, lockExpirationTime: new Date(null), state: data.state ?? processcube_engine_sdk_1.ExternalTaskState.pending, }); externalTask = await index_2.ExternalTaskModel.findOne({ where: { flowNodeInstanceId: data.flowNodeInstanceId, }, include: this.getJoinsForSelectQuery(), }); } return await this.convertToRuntimeObject(externalTask); }, `ensure external task for flow node instance id ${data.flowNodeInstanceId} is created`); } async deleteExternalTaskByExternalTaskId(externalTaskId) { await index_2.ExternalTaskModel.destroy({ where: { externalTaskId, }, }); } async fetchAvailableForProcessing(topicNames, maxTasks, payloadFilter) { const offset = 0; let limit = 0; if (!payloadFilter) { limit = maxTasks; } const topicNamesArray = [topicNames].flat(); const options = { include: this.getJoinsForSelectQuery(), where: { topic: topicNamesArray, state: processcube_engine_sdk_1.ExternalTaskState.pending, lockExpirationTime: new Date(null), }, ...(0, SearchQueryBuilder_1.buildPagination)(offset, limit), }; const results = await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => index_2.ExternalTaskModel.findAll(options), `fetch available external tasks for topics: '${topicNamesArray.join(', ')}'`); let externalTasks = []; for (const rawExternalTask of results) { const externalTask = await this.convertToRuntimeObject(rawExternalTask); externalTasks.push(externalTask); } if (payloadFilter) { return this.applyPayloadFilter(externalTasks, payloadFilter, maxTasks); } return externalTasks; } async lockForWorker(workerId, externalTaskIds, lockExpirationTime) { await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => { await index_2.ExternalTaskModel.update({ workerId: workerId, lockExpirationTime: lockExpirationTime, }, { where: { externalTaskId: { [sequelize_1.Op.in]: externalTaskIds, }, }, }); }, `Lock external tasks '${externalTaskIds}' for worker '${workerId}'`); } async unlockExternalTasks(externalTaskIds) { await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => { await index_2.ExternalTaskModel.update({ workerId: null, lockExpirationTime: new Date(null), }, { where: { externalTaskId: { [sequelize_1.Op.in]: externalTaskIds, }, }, }); }, `Unlock external tasks '${externalTaskIds}'`); } async getExternalTasksWithActiveLock() { const externalTaskModels = await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => { return index_2.ExternalTaskModel.findAll({ where: { lockExpirationTime: { [sequelize_1.Op.not]: new Date(null) }, state: processcube_engine_sdk_1.ExternalTaskState.pending, }, include: this.getJoinsForSelectQuery(), }); }, 'find all pending external tasks with no lock expiration time'); return Promise.all(externalTaskModels.map(async (externalTaskModel) => this.convertToRuntimeObject(externalTaskModel))); } async setExternalTaskLockExpired(externalTaskId) { const externalTask = await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => { return index_2.ExternalTaskModel.findOne({ where: { externalTaskId: externalTaskId, }, include: this.getJoinsForSelectQuery(), }); }, `Find one external task for external task id '${externalTaskId}'`); if (!externalTask || externalTask.flowNodeInstance.state != processcube_engine_sdk_1.FlowNodeInstanceState.suspended) { return; } if (externalTask.isSingleTry) { const externalTaskExpiredMessage = index_1.eventAggregatorSettings.messagePaths.externalTaskExpired; EventAggregator_1.default.publish(externalTaskExpiredMessage, { externalTaskId: externalTaskId }); } else { externalTask.workerId = null; externalTask.lockExpirationTime = new Date(null); await (0, SequelizeConnectionManager_1.executeWithRetry)(async () => { await externalTask.save(); }, 'saving external task with empty lock expiration time'); const payload = { externalTaskId: externalTask.externalTaskId, topic: externalTask.topic, correlationId: externalTask.flowNodeInstance.correlationId, processDefinitionId: externalTask.flowNodeInstance.processDefinitionId, processModelId: externalTask.flowNodeInstance.processModelId, embeddedProcessModelId: externalTask.flowNodeInstance.embeddedProcessModelId, processInstanceId: externalTask.flowNodeInstance.processInstanceId, flowNodeInstanceId: externalTask.flowNodeInstanceId, }; EventAggregator_1.default.publish(index_1.eventAggregatorSettings.messagePaths.externalTaskUnlocked, payload); } } getJoinsForSelectQuery() { return [ { model: index_2.FlowNodeInstanceModel, as: 'flowNodeInstance', required: true, attributes: [ 'startToken', 'startTokenCompressed', 'endToken', 'endTokenCompressed', 'error', 'correlationId', 'processDefinitionId', 'processModelId', 'embeddedProcessModelId', 'processInstanceId', 'state', 'ownerId', ], }, ]; } async convertToRuntimeObject(dataModel) { let externalTaskPayload; if (dataModel.flowNodeInstance.startToken) { externalTaskPayload = this.tryParse(dataModel.flowNodeInstance.startToken); } else if (dataModel.flowNodeInstance.startTokenCompressed) { externalTaskPayload = await (0, Compression_1.decompressToken)(dataModel.flowNodeInstance.startTokenCompressed); } let externalTaskResult; if (dataModel.flowNodeInstance.endToken) { externalTaskResult = this.tryParse(dataModel.flowNodeInstance.endToken); } else if (dataModel.flowNodeInstance.endTokenCompressed) { externalTaskResult = await (0, Compression_1.decompressToken)(dataModel.flowNodeInstance.endTokenCompressed); } let error; if (dataModel.flowNodeInstance?.error) { error = (0, processcube_engine_sdk_1.deserializeJson)(dataModel.flowNodeInstance.error); } const externalTask = { id: dataModel.externalTaskId, workerId: dataModel.workerId, topic: dataModel.topic, isSingleTry: dataModel.isSingleTry, flowNodeInstanceId: dataModel.flowNodeInstanceId, correlationId: dataModel.flowNodeInstance.correlationId, processDefinitionId: dataModel.flowNodeInstance.processDefinitionId, processModelId: dataModel.flowNodeInstance.processModelId, embeddedProcessModelId: dataModel.flowNodeInstance.embeddedProcessModelId, processInstanceId: dataModel.flowNodeInstance.processInstanceId, ownerId: dataModel.flowNodeInstance.ownerId, payload: externalTaskPayload, lockExpirationTime: dataModel.lockExpirationTime, state: dataModel.flowNodeInstance.state === processcube_engine_sdk_1.FlowNodeInstanceState.suspended ? processcube_engine_sdk_1.ExternalTaskState.pending : processcube_engine_sdk_1.ExternalTaskState.finished, finishedAt: dataModel.finishedAt, error: error, result: externalTaskResult, createdAt: dataModel.createdAt, }; return externalTask; } applyPayloadFilter(externalTasks, payloadFilter, maxTasks) { const filteredExternalTasks = externalTasks.filter((externalTask) => { const stringifiedPayload = JSON.stringify(externalTask.payload); const isMatch = payloadFilter.test(stringifiedPayload); return isMatch; }); if (maxTasks > 0) { return filteredExternalTasks.splice(0, maxTasks); } return filteredExternalTasks; } tryParse(value) { if (!value) { return value; } try { return JSON.parse(value); } catch (error) { // Value is not a JSON - return it as it is. return value; } } }; exports.ExternalTaskDatabaseAdapter = ExternalTaskDatabaseAdapter; exports.ExternalTaskDatabaseAdapter = ExternalTaskDatabaseAdapter = __decorate([ (0, inversify_1.injectable)() ], ExternalTaskDatabaseAdapter); //# sourceMappingURL=ExternalTaskAdapter.js.map