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