@nocobase/plugin-workflow
Version:
A powerful BPM tool that provides foundational support for business automation, with the capability to extend unlimited triggers and nodes.
192 lines (190 loc) • 7.54 kB
JavaScript
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var utils_exports = {};
__export(utils_exports, {
abortExecution: () => abortExecution,
getExecutionLockKey: () => getExecutionLockKey,
getExecutionStatusName: () => getExecutionStatusName,
getWorkflowExecutionLogMeta: () => getWorkflowExecutionLogMeta,
isLockAcquireError: () => isLockAcquireError,
toJSON: () => toJSON,
validateCollectionField: () => validateCollectionField
});
module.exports = __toCommonJS(utils_exports);
var import_database = require("@nocobase/database");
var import_data_source_manager = require("@nocobase/data-source-manager");
var import_constants = require("./constants");
function getExecutionLockKey(executionId) {
return `workflow:execution:${executionId}`;
}
function isLockAcquireError(error) {
return error instanceof Error && error.constructor.name === "LockAcquireError";
}
function afterTransactionCommit(transaction, callback) {
if (typeof transaction.afterCommit === "function") {
transaction.afterCommit(callback);
return;
}
callback();
}
function validateCollectionField(collection, dataSourceManager) {
const [dataSourceName, collectionName] = (0, import_data_source_manager.parseCollectionName)(collection);
if (!dataSourceName || !collectionName) {
return { collection: `"collection" must be in the format "dataSourceName:collectionName"` };
}
const dataSource = dataSourceManager.dataSources.get(dataSourceName);
if (!dataSource) {
return { collection: `Data source "${dataSourceName}" does not exist` };
}
if (!dataSource.collectionManager.getCollection(collectionName)) {
return { collection: `Collection "${collectionName}" does not exist in data source "${dataSourceName}"` };
}
return null;
}
const EXECUTION_STATUS_NAMES = new Map(Object.entries(import_constants.EXECUTION_STATUS).map(([name, value]) => [value, name]));
function getExecutionStatusName(status) {
if (typeof status === "undefined") {
return "UNKNOWN";
}
return EXECUTION_STATUS_NAMES.get(status) ?? `${status}`;
}
function getWorkflowExecutionLogMeta(workflow, processor) {
var _a, _b, _c, _d;
const lastSavedJob = processor == null ? void 0 : processor.lastSavedJob;
const lastNode = (_a = processor == null ? void 0 : processor.nodesMap) == null ? void 0 : _a.get(lastSavedJob == null ? void 0 : lastSavedJob.nodeId);
return {
workflowId: workflow.id,
workflowKey: workflow.key,
workflowTitle: workflow.title,
executionId: ((_b = processor == null ? void 0 : processor.execution) == null ? void 0 : _b.id) ?? null,
executionStatus: ((_c = processor == null ? void 0 : processor.execution) == null ? void 0 : _c.status) ?? null,
executionStatusName: getExecutionStatusName((_d = processor == null ? void 0 : processor.execution) == null ? void 0 : _d.status),
lastNodeId: (lastNode == null ? void 0 : lastNode.id) ?? (lastSavedJob == null ? void 0 : lastSavedJob.nodeId) ?? null,
lastNodeType: (lastNode == null ? void 0 : lastNode.type) ?? null,
lastJobId: (lastSavedJob == null ? void 0 : lastSavedJob.id) ?? null,
lastJobStatus: (lastSavedJob == null ? void 0 : lastSavedJob.status) ?? null
};
}
async function abortExecution(plugin, execution, options = {}) {
const logger = plugin.getLogger(execution.workflowId);
const transaction = options.transaction ?? void 0;
const ExecutionRepo = plugin.db.getRepository("executions");
const JobRepo = plugin.db.getRepository("jobs");
try {
if (!transaction) {
return plugin.db.sequelize.transaction(
(transaction2) => abortExecution(plugin, execution, {
...options,
transaction: transaction2
})
);
}
const abortValues = {
status: import_constants.EXECUTION_STATUS.ABORTED,
...options.reason ? {
reason: options.reason
} : {}
};
const expectedStatus = typeof execution.status === "undefined" ? import_constants.EXECUTION_STATUS.STARTED : execution.status;
if (![import_constants.EXECUTION_STATUS.QUEUEING, import_constants.EXECUTION_STATUS.STARTED].includes(expectedStatus)) {
return false;
}
const [affected] = await ExecutionRepo.model.update(abortValues, {
where: {
id: execution.id,
status: expectedStatus
},
individualHooks: true,
transaction
});
if (!affected) {
return false;
}
const updated = await JobRepo.update({
values: {
status: import_constants.JOB_STATUS.ABORTED
},
filter: {
executionId: execution.id,
status: import_constants.JOB_STATUS.PENDING
},
individualHooks: false,
transaction
});
const childExecutions = await plugin.db.getRepository("executions").find({
filter: {
parentExecutionId: execution.id,
status: [import_constants.EXECUTION_STATUS.QUEUEING, import_constants.EXECUTION_STATUS.STARTED]
},
transaction
});
for (const child of childExecutions) {
if (![import_constants.EXECUTION_STATUS.QUEUEING, import_constants.EXECUTION_STATUS.STARTED].includes(child.status)) {
continue;
}
await abortExecution(plugin, child, { transaction, reason: import_constants.EXECUTION_REASON.PARENT_ABORTED });
}
const updateLocalState = () => {
execution.set("status", import_constants.EXECUTION_STATUS.ABORTED);
execution.set("reason", options.reason ?? null);
plugin.timeoutManager.clear(execution.id);
plugin.abortRunningExecution(execution.id, options.reason);
};
afterTransactionCommit(transaction, updateLocalState);
logger.info(`execution (${execution.id}) aborted`, {
workflowId: execution.workflowId,
pendingJobs: Array.isArray(updated) ? updated.length : updated
});
return true;
} catch (error) {
throw error;
}
}
function toJSON(data) {
if (Array.isArray(data)) {
return data.map(toJSON);
}
if (!(data instanceof import_database.Model) || !data) {
return data;
}
const result = data.get();
Object.keys(data.constructor.associations).forEach((key) => {
if (result[key] != null && typeof result[key] === "object") {
result[key] = toJSON(result[key]);
}
});
return result;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
abortExecution,
getExecutionLockKey,
getExecutionStatusName,
getWorkflowExecutionLogMeta,
isLockAcquireError,
toJSON,
validateCollectionField
});