@5minds/processcube_engine
Version:
The ProcessCube Engine. Stores and executes BPMNs.
289 lines • 12 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.workerThreadNames = exports.workerThreadIds = void 0;
exports.registerOnBeforeResumingCallback = registerOnBeforeResumingCallback;
exports.clearOnReadyCallbacks = clearOnReadyCallbacks;
exports.registerOnReadyCallback = registerOnReadyCallback;
exports.getOnBeforeResumingCallbacks = getOnBeforeResumingCallbacks;
exports.getOnReadyCallbacks = getOnReadyCallbacks;
exports.isSQLite = isSQLite;
exports.isWindows = isWindows;
exports.getBeautifiedThreadName = getBeautifiedThreadName;
exports.getThreadName = getThreadName;
exports.getExtensionDir = getExtensionDir;
exports.isWindowsAndSQLite = isWindowsAndSQLite;
exports.loadConfig = loadConfig;
exports.calculateMaxPoolSize = calculateMaxPoolSize;
exports.getSqlitePath = getSqlitePath;
exports.getUserConfigFolder = getUserConfigFolder;
exports.readConfigFile = readConfigFile;
exports.getConfig = getConfig;
exports.getReleaseChannel = getReleaseChannel;
exports.readPackageJson = readPackageJson;
exports.setWorkingDirectory = setWorkingDirectory;
exports.getWorkingDirectory = getWorkingDirectory;
const child_process_1 = require("child_process");
const fs_1 = __importDefault(require("fs"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk");
const Configurator_1 = __importDefault(require("./Configurator"));
const logger = new processcube_engine_sdk_1.Logger('application');
exports.workerThreadIds = {
main: 'main',
fetchAndLock: 'fetchAndLock',
query: 'query',
runtime: 'runtime',
};
exports.workerThreadNames = {
main: 'main',
fetchAndLock: 'ExternalTasks',
query: 'QueryRequests',
runtime: 'ProcessExecution',
};
const dbConnectionWeightsPerThread = {
[exports.workerThreadIds.main]: 0,
[exports.workerThreadIds.fetchAndLock]: 0.3,
[exports.workerThreadIds.query]: 0.3,
[exports.workerThreadIds.runtime]: 0.4,
};
let thread = exports.workerThreadIds.main;
const onBeforeResumingCallbacks = [];
let onReadyCallbacks = [];
let configuredSqlitePath;
let workingDirectory = path_1.default.resolve(path_1.default.join(getUserConfigFolder(), '.processcube', 'engine'));
function registerOnBeforeResumingCallback(callback) {
onBeforeResumingCallbacks.push(callback);
}
function clearOnReadyCallbacks() {
onReadyCallbacks = [];
}
function registerOnReadyCallback(callback) {
onReadyCallbacks.push(callback);
}
function getOnBeforeResumingCallbacks() {
return onBeforeResumingCallbacks;
}
function getOnReadyCallbacks() {
return onReadyCallbacks;
}
function isSQLite() {
const databaseConfig = Configurator_1.default.database();
return databaseConfig.dialect === 'sqlite';
}
function isWindows() {
return process.platform === 'win32';
}
function getBeautifiedThreadName() {
return exports.workerThreadNames[getThreadName()];
}
function getThreadName() {
return thread;
}
function getExtensionDir() {
const extensionsDir = process.env.extensionsDir || path_1.default.join(workingDirectory, 'extensions');
const normalizedDir = path_1.default.normalize(extensionsDir);
return path_1.default.resolve(normalizedDir);
}
function isWindowsAndSQLite() {
return isSQLite() && isWindows();
}
async function loadConfig(workerName) {
thread = workerName;
configuredSqlitePath = process.env.sqlitePath;
if (!process.env.appRootDir) {
process.env.appRootDir = path_1.default.resolve(__dirname, '..', '..');
}
if (!process.env.CONFIG_PATH) {
const defaultConfigPath = path_1.default.resolve(process.env.appRootDir, 'configs', 'sqlite.json');
logger.info(`Using Default Config File: '${defaultConfigPath}'`);
process.env.CONFIG_PATH = defaultConfigPath;
}
const configFile = readConfigFile();
setWorkingDirectory();
const sqliteUsed = (process.env.database__dialect || configFile.database.dialect) === 'sqlite';
if (sqliteUsed) {
const sqlitePathFromConfig = process.env.database__storage || configFile.database.storage;
configureSqlite(configuredSqlitePath ?? sqlitePathFromConfig);
}
Configurator_1.default.initialize(process.env.CONFIG_PATH, getReleaseChannel());
const minLogLevel = Configurator_1.default.logging()?.minLogLevel;
process.env.minLogLevel = minLogLevel || processcube_engine_sdk_1.LogLevel.debug;
process.env.hostname = await getHostname();
if (workerName) {
(0, processcube_engine_sdk_1.setGlobalLogObjects)({
worker: workerName,
});
}
}
function calculateMaxPoolSize(dbPoolConfig) {
if (!dbPoolConfig) {
return 0;
}
validateDatabasePoolSizeSettings(dbPoolConfig);
const maxGlobalPoolSizeSet = !!dbPoolConfig.max;
const workerSpecificPoolSizesSet = dbPoolConfig.maxForExternalTasks || dbPoolConfig.maxForQueryRequests || dbPoolConfig.maxForProcessExecution;
if (maxGlobalPoolSizeSet) {
return Math.floor(dbPoolConfig.max * dbConnectionWeightsPerThread[thread]);
}
if (workerSpecificPoolSizesSet) {
switch (thread) {
case exports.workerThreadIds.main:
return 0;
case exports.workerThreadIds.fetchAndLock:
return dbPoolConfig.maxForExternalTasks;
case exports.workerThreadIds.query:
return dbPoolConfig.maxForQueryRequests;
case exports.workerThreadIds.runtime:
return dbPoolConfig.maxForProcessExecution;
}
}
}
function validateDatabasePoolSizeSettings(dbPoolConfig) {
const maxGlobalPoolSizeSet = !!dbPoolConfig.max;
const workerSpecificPoolSizesSet = dbPoolConfig.maxForExternalTasks || dbPoolConfig.maxForQueryRequests || dbPoolConfig.maxForProcessExecution;
const isMissingAWorkerSpecificPoolSize = !(dbPoolConfig.maxForExternalTasks && dbPoolConfig.maxForQueryRequests && dbPoolConfig.maxForProcessExecution);
if (maxGlobalPoolSizeSet && workerSpecificPoolSizesSet) {
const errorMessage = `
Failure in Setup: Cannot configure an overall "max" db connection pool size in conjunction with worker-specific connection pool sizes.
Currentl configuration:
${JSON.stringify(dbPoolConfig)}
To fix this, either use database.pool.max OR database.pool.maxForExternalTasks with database.pool.maxForQueryRequests and database.pool.maxForProcessExecution OR remove the settings altogether.
Either use
"pool": {
"max": 100
}
OR:
"pool": {
"maxForExternalTasks": 30,
"maxForQueryRequests": 30,
"maxForProcessExecution": 40
}`;
const conflictingSettingsError = new processcube_engine_sdk_1.UnprocessableEntityError(errorMessage);
conflictingSettingsError.category = 'setup';
conflictingSettingsError.additionalInformation = {
currentConfiguration: dbPoolConfig,
};
throw conflictingSettingsError;
}
if (workerSpecificPoolSizesSet && isMissingAWorkerSpecificPoolSize) {
const errorMessage = `
Failure in Setup: A db connection pool setting is missing.
Currently configured:
${JSON.stringify(dbPoolConfig)}
To fix this, you must provide values for database.pool.maxForExternalTasks, database.pool.maxForQueryRequests and database.pool.maxForProcessExecution, or you can remove the settings altogether.
Example:
"pool": {
"maxForExternalTasks": 30,
"maxForQueryRequests": 30,
"maxForProcessExecution": 40
}`;
const settingsMissingError = new processcube_engine_sdk_1.UnprocessableEntityError(errorMessage);
settingsMissingError.category = 'setup';
settingsMissingError.additionalInformation = {
currentConfiguration: dbPoolConfig,
};
throw settingsMissingError;
}
}
async function getHostname() {
return new Promise((resolve) => {
(0, child_process_1.exec)('hostname', (error, result) => {
if (error) {
logger.warn(`Failed to retrieve hostname: ${error.message}`, { err: error });
return resolve('N/A');
}
return resolve(result?.trim());
});
});
}
function getSqlitePath() {
return configuredSqlitePath;
}
function getUserConfigFolder() {
return os_1.default.homedir();
}
function readConfigFile() {
const configFilePath = path_1.default.resolve(process.env.CONFIG_PATH);
const fileContent = fs_1.default.readFileSync(configFilePath, 'utf-8');
const parsedFileContent = JSON.parse(fileContent);
return parsedFileContent;
}
function getConfig() {
return {
httpServer: Configurator_1.default.httpServer(),
logging: Configurator_1.default.logging(),
database: Configurator_1.default.database(),
iam: Configurator_1.default.iam(),
application: Configurator_1.default.application(),
};
}
function getReleaseChannel() {
const nodeEnv = process.env.NODE_ENV?.toLowerCase();
const isDev = nodeEnv == 'dev' || nodeEnv == 'develop' || nodeEnv == 'development' || nodeEnv == 'test';
if (isDev) {
return 'dev';
}
const version = readPackageJson().version;
if (version.includes('alpha')) {
return 'alpha';
}
if (version.includes('beta')) {
return 'beta';
}
return 'stable';
}
function readPackageJson() {
const pathToPackageJson = path_1.default.join(process.env.appRootDir, 'package.json');
const packageJsonAsString = fs_1.default.readFileSync(pathToPackageJson, 'utf-8');
const packageJson = JSON.parse(packageJsonAsString);
return packageJson;
}
function setWorkingDirectory() {
const customWorkDir = process.env.workDir;
if (!customWorkDir) {
configureDefaultWorkDir();
logger.debug(`Using default working directory: ${workingDirectory}`);
return;
}
const resolvedCustomWorkDir = path_1.default.resolve(customWorkDir);
if (!fs_1.default.existsSync(resolvedCustomWorkDir)) {
fs_1.default.mkdirSync(resolvedCustomWorkDir, { recursive: true });
}
workingDirectory = resolvedCustomWorkDir;
logger.debug(`Using working directory: ${workingDirectory}`);
}
function getWorkingDirectory() {
return workingDirectory;
}
function configureSqlite(customSqliteStoragePath) {
configuredSqlitePath = resolveSqliteStoragePath(customSqliteStoragePath);
process.env.database__storage = configuredSqlitePath;
}
function resolveSqliteStoragePath(customSqliteStoragePath) {
const defaultSqlitePath = workingDirectory;
let pathToUse = path_1.default.isAbsolute(customSqliteStoragePath) ? customSqliteStoragePath : path_1.default.join(defaultSqlitePath, customSqliteStoragePath);
if (fs_1.default.existsSync(pathToUse) && fs_1.default.lstatSync(pathToUse).isDirectory()) {
pathToUse = path_1.default.join(pathToUse, 'engine.sqlite');
}
return path_1.default.resolve(pathToUse);
}
function configureDefaultWorkDir() {
const defaultWorkDir = path_1.default.join(getUserConfigFolder(), '.processcube', 'engine');
const legacyWorkDir = path_1.default.join(getUserConfigFolder(), '.atlas', 'engine');
const legacyWorkDirDoesNotExist = !fs_1.default.existsSync(legacyWorkDir);
if (legacyWorkDirDoesNotExist) {
workingDirectory = defaultWorkDir;
return;
}
const defaultWorkDirExists = fs_1.default.existsSync(defaultWorkDir);
if (defaultWorkDirExists) {
throw new Error(`Found both working directories \`${legacyWorkDir}\` and \`${defaultWorkDir}\`.\n\nPlease rename/remove \`${legacyWorkDir}\` in favor of \`${defaultWorkDir}\`.`);
}
logger.warn(`Using legacy working directory '${legacyWorkDir}'.\n\nPlease rename '${legacyWorkDir}' to '${defaultWorkDir}'.`);
workingDirectory = legacyWorkDir;
}
//# sourceMappingURL=Environment.js.map