ЦИТК-659 - Возможность работы нескольких серверов параллельно #9

Merged
Mim merged 7 commits from Dollerok/P8-ExchangeService:master into master 2025-06-03 16:56:18 +03:00
7 changed files with 202 additions and 108 deletions

View File

@ -9,6 +9,8 @@
//Общие параметры //Общие параметры
let common = { let common = {
//Наименование сервера приложений
sServerName: "",
//Версия сервера приложений //Версия сервера приложений
sVersion: "8.5.6.1", sVersion: "8.5.6.1",
//Релиз сервера приложений //Релиз сервера приложений

View File

@ -201,13 +201,20 @@ class ParusAppServer {
this.dbConn = new db.DBConnector({ this.dbConn = new db.DBConnector({
connectSettings: { connectSettings: {
...prms.config.dbConnect, ...prms.config.dbConnect,
exsSrv: {
sServerName: prms.config.common.sServerName,
sServerIP: `${prms.config.inComing.nPort};${
prms.config.inComing.sHost === "0.0.0.0" ? getIPs().join(";") : prms.config.inComing.sHost
}`
},
sRelease: prms.config.common.sRelease, sRelease: prms.config.common.sRelease,
bControlSystemVersion: prms.config.common.bControlSystemVersion, bControlSystemVersion: prms.config.common.bControlSystemVersion,
nPoolMin: prms.config.inComing.nPoolMin, nPoolMin: prms.config.inComing.nPoolMin,
nPoolMax: prms.config.inComing.nPoolMax, nPoolMax: prms.config.inComing.nPoolMax,
nPoolIncrement: prms.config.inComing.nPoolIncrement, nPoolIncrement: prms.config.inComing.nPoolIncrement,
nMaxWorkers: prms.config.outGoing.nMaxWorkers nMaxWorkers: prms.config.outGoing.nMaxWorkers
} },
bServer: true
}); });
//Создаём модуль рассылки уведомлений //Создаём модуль рассылки уведомлений
this.notifier = new ntf.Notifier({ logger: this.logger, mail: prms.config.mail }); this.notifier = new ntf.Notifier({ logger: this.logger, mail: prms.config.mail });

View File

@ -73,6 +73,8 @@ class DBConnector extends EventEmitter {
//Инициализируем остальные свойства //Инициализируем остальные свойства
this.connection = null; this.connection = null;
this.bConnected = false; this.bConnected = false;
this.nExsSrv = null;
this.bServer = prms.bServer === true ? true : false;
} else { } else {
throw new ServerError(SERR_MODULES_NO_MODULE_SPECIFIED, "Не указано имя подключаемого модуля-коннектора!"); throw new ServerError(SERR_MODULES_NO_MODULE_SPECIFIED, "Не указано имя подключаемого модуля-коннектора!");
} }
@ -100,6 +102,28 @@ class DBConnector extends EventEmitter {
try { try {
//Подключаемся //Подключаемся
this.connection = await this.connector.connect(this.connectSettings); this.connection = await this.connector.connect(this.connectSettings);
//Если это запуск сервиса интеграции
if (this.bServer) {
//Проверяем общие условия запуска
await this.connector.checkAppStart({
bControlSystemVersion: this.connectSettings.bControlSystemVersion,
sRelease: this.connectSettings.sRelease,
nWorkers: this.connectSettings.nMaxWorkers,
sServerName: this.connectSettings.exsSrv.sServerName,
sSessionAppName: this.connectSettings.sSessionAppName,
connection: this.connection
});
//Если сервис интеграции разделяется на сервера
if (this.connectSettings.exsSrv.sServerName) {
//Инициализируем информацию о сервере интеграции
this.nExsSrv = await this.connector.initServer({
sServerName: this.connectSettings.exsSrv.sServerName,
sServerIP: this.connectSettings.exsSrv.sServerIP,
nMaxWorkers: this.connectSettings.nMaxWorkers,
connection: this.connection
});
}
}
//Выставим внутренний флаг подключения //Выставим внутренний флаг подключения
this.bConnected = true; this.bConnected = true;
//Расскажем всем, что подключились //Расскажем всем, что подключились
@ -116,6 +140,11 @@ class DBConnector extends EventEmitter {
//Смысл отключаться есть только когда мы подключены, в противном случае - зачем тратить время //Смысл отключаться есть только когда мы подключены, в противном случае - зачем тратить время
if (this.bConnected) { if (this.bConnected) {
try { try {
//Если указана информация о сервере и это закрытие сервиса интеграции
if (this.nExsSrv && this.bServer) {
//Очищаем информацию о сервере
await this.connector.clearServer({ nExsSrv: this.nExsSrv, connection: this.connection });
}
//Отключаемся //Отключаемся
await this.connector.disconnect({ connection: this.connection }); await this.connector.disconnect({ connection: this.connection });
//Забываем подключение и удаляем флаги подключенности //Забываем подключение и удаляем флаги подключенности
@ -136,7 +165,7 @@ class DBConnector extends EventEmitter {
if (this.bConnected) { if (this.bConnected) {
try { try {
//Забираем список сервисов и декорируем его заготовками под список функций //Забираем список сервисов и декорируем его заготовками под список функций
let srvs = await this.connector.getServices({ connection: this.connection }); let srvs = await this.connector.getServices({ connection: this.connection, nExsSrv: this.nExsSrv });
srvs.forEach(s => { srvs.forEach(s => {
s.functions = []; s.functions = [];
}); });
@ -386,6 +415,7 @@ class DBConnector extends EventEmitter {
//Подготовим параметры для передачи в БД //Подготовим параметры для передачи в БД
let logData = _.cloneDeep(prms); let logData = _.cloneDeep(prms);
logData.connection = this.connection; logData.connection = this.connection;
logData.nExsSrv = this.nExsSrv;
//И выполним запись в журнал //И выполним запись в журнал
let res = await this.connector.log(logData); let res = await this.connector.log(logData);
//Валидируем полученный ответ //Валидируем полученный ответ
@ -521,6 +551,7 @@ class DBConnector extends EventEmitter {
//Подготовим параметры для передачи в БД //Подготовим параметры для передачи в БД
let getQueueOutgoingData = _.cloneDeep(prms); let getQueueOutgoingData = _.cloneDeep(prms);
getQueueOutgoingData.connection = this.connection; getQueueOutgoingData.connection = this.connection;
getQueueOutgoingData.nExsSrv = this.nExsSrv;
//Выполняем считывание из БД //Выполняем считывание из БД
let res = await this.connector.getQueueOutgoing(getQueueOutgoingData); let res = await this.connector.getQueueOutgoing(getQueueOutgoingData);
//Валидируем полученный ответ //Валидируем полученный ответ

View File

@ -13,6 +13,9 @@ const Schema = require("validate"); //Схемы валидации
// Тело модуля // Тело модуля
//------------- //-------------
//Функция проверки длины значения наименование сервера приложений
const validateServerName = val => val.length <= 40;
//Функция проверки значения таймаута останова сервера //Функция проверки значения таймаута останова сервера
const validateTerminateTimeout = val => val >= 1000 && val <= 120000 && Number.isInteger(val); const validateTerminateTimeout = val => val >= 1000 && val <= 120000 && Number.isInteger(val);
@ -48,6 +51,16 @@ const validatePoolIncrementInComing = val => val >= 0 && val <= 1000;
//Схема валидации общих параметров сервера приложений //Схема валидации общих параметров сервера приложений
const common = new Schema({ const common = new Schema({
//Наименование сервера приложений
sServerName: {
type: String,
required: false,
use: { validateServerName },
message: {
type: path => `Наименование сервера приложений (${path}) имеет некорректный тип данных (ожидалось - String)`,
validateServerName: path => `Длина наименования сервера приложений (${path}) не может превышать 40 символов`
}
},
//Версия сервера приложений //Версия сервера приложений
sVersion: { sVersion: {
type: String, type: String,

View File

@ -174,8 +174,7 @@ exports.putServiceAuthInQueue = new Schema({
required: false, required: false,
enum: [NFORCE_YES, NFORCE_NO], enum: [NFORCE_YES, NFORCE_NO],
message: { message: {
type: path => type: path => `Признак принудительного завершения сессии (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Признак принудительного завершения сессии (${path}) имеет некорректный тип данных (ожидалось - Number)`,
enum: path => `Значение признака принудительного завершения сессии (${path}) не поддерживается`, enum: path => `Значение признака принудительного завершения сессии (${path}) не поддерживается`,
required: path => `Не указан признак принудительного завершения сессии (${path})` required: path => `Не указан признак принудительного завершения сессии (${path})`
} }
@ -203,8 +202,7 @@ exports.putLog = new Schema({
enum: [NLOG_STATE_INF, NLOG_STATE_WRN, NLOG_STATE_ERR], enum: [NLOG_STATE_INF, NLOG_STATE_WRN, NLOG_STATE_ERR],
required: true, required: true,
message: { message: {
type: path => type: path => `Тип сообщения журнала работы сервиса (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Тип сообщения журнала работы сервиса (${path}) имеет некорректный тип данных (ожидалось - Number)`,
enum: path => `Значение типа сообщения журнала работы сервиса (${path}) не поддерживается`, enum: path => `Значение типа сообщения журнала работы сервиса (${path}) не поддерживается`,
required: path => `Не указан тип сообщения журнала работы сервиса (${path})` required: path => `Не указан тип сообщения журнала работы сервиса (${path})`
} }
@ -214,8 +212,7 @@ exports.putLog = new Schema({
type: String, type: String,
required: false, required: false,
message: { message: {
type: path => type: path => `Сообщение журнала работы сервиса (${path}) имеет некорректный тип данных (ожидалось - String)`,
`Сообщение журнала работы сервиса (${path}) имеет некорректный тип данных (ожидалось - String)`,
required: path => `Не указано сообщение журнала работы сервиса (${path})` required: path => `Не указано сообщение журнала работы сервиса (${path})`
} }
}, },
@ -236,8 +233,7 @@ exports.putLog = new Schema({
message: { message: {
type: path => type: path =>
`Идентификатор связанной функции-обработчика сообщения журнала работы сервиса (${path}) имеет некорректный тип данных (ожидалось - Number)`, `Идентификатор связанной функции-обработчика сообщения журнала работы сервиса (${path}) имеет некорректный тип данных (ожидалось - Number)`,
required: path => required: path => `Не указан идентификатор связанной функции-обработчика сообщения журнала работы сервиса (${path})`
`Не указан идентификатор связанной функции-обработчика сообщения журнала работы сервиса (${path})`
} }
}, },
//Идентификатор связанной позиции очереди обмена //Идентификатор связанной позиции очереди обмена
@ -247,8 +243,7 @@ exports.putLog = new Schema({
message: { message: {
type: path => type: path =>
`Идентификатор связанной позиции очереди обмена сообщения журнала работы сервиса (${path}) имеет некорректный тип данных (ожидалось - Number)`, `Идентификатор связанной позиции очереди обмена сообщения журнала работы сервиса (${path}) имеет некорректный тип данных (ожидалось - Number)`,
required: path => required: path => `Не указан идентификатор связанной позиции очереди обмена сообщения журнала работы сервиса (${path})`
`Не указан идентификатор связанной позиции очереди обмена сообщения журнала работы сервиса (${path})`
} }
} }
}); });
@ -260,8 +255,7 @@ exports.getQueue = new Schema({
type: Number, type: Number,
required: true, required: true,
message: { message: {
type: path => type: path => `Идентификатор позиции очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Идентификатор позиции очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
required: path => `Не указан идентификатор позиции очереди обмена (${path})` required: path => `Не указан идентификатор позиции очереди обмена (${path})`
} }
} }
@ -274,8 +268,7 @@ exports.putQueue = new Schema({
type: Number, type: Number,
required: true, required: true,
message: { message: {
type: path => type: path => `Идентификатор функции сервиса обработчика позиции очереди (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Идентификатор функции сервиса обработчика позиции очереди (${path}) имеет некорректный тип данных (ожидалось - Number)`,
required: path => `Не указан идентификатор функции сервиса обработчика позиции очереди (${path})` required: path => `Не указан идентификатор функции сервиса обработчика позиции очереди (${path})`
} }
}, },
@ -284,8 +277,7 @@ exports.putQueue = new Schema({
use: { validateBuffer }, use: { validateBuffer },
required: false, required: false,
message: { message: {
validateBuffer: path => validateBuffer: path => `Данные сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
`Данные сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
required: path => `Не указаны данные сообщения очереди обмена (${path})` required: path => `Не указаны данные сообщения очереди обмена (${path})`
} }
}, },
@ -294,8 +286,7 @@ exports.putQueue = new Schema({
type: Number, type: Number,
required: false, required: false,
message: { message: {
type: path => type: path => `Идентификатор связанной позиции очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Идентификатор связанной позиции очереди обмена (${path}) имеет некорректный тип данных (ожидалось - Number)`,
required: path => `Не указан идентификатор связанной позиции очереди обмена (${path})` required: path => `Не указан идентификатор связанной позиции очереди обмена (${path})`
} }
}, },
@ -304,8 +295,7 @@ exports.putQueue = new Schema({
type: Number, type: Number,
required: false, required: false,
message: { message: {
type: path => type: path => `Идентификатор связанной организации (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Идентификатор связанной организации (${path}) имеет некорректный тип данных (ожидалось - Number)`,
required: path => `Не указан идентификатор связанной организации (${path})` required: path => `Не указан идентификатор связанной организации (${path})`
} }
}, },
@ -314,8 +304,7 @@ exports.putQueue = new Schema({
type: Number, type: Number,
required: false, required: false,
message: { message: {
type: path => type: path => `Идентификатор связанного документа (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Идентификатор связанного документа (${path}) имеет некорректный тип данных (ожидалось - Number)`,
required: path => `Не указан идентификатор связанного документа (${path})` required: path => `Не указан идентификатор связанного документа (${path})`
} }
}, },
@ -346,8 +335,7 @@ exports.getOutgoing = new Schema({
type: Number, type: Number,
required: true, required: true,
message: { message: {
type: path => type: path => `Количество считываемых сообщений очереди (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Количество считываемых сообщений очереди (${path}) имеет некорректный тип данных (ожидалось - Number)`,
required: path => `Не указано количество считываемых сообщений очереди (${path})` required: path => `Не указано количество считываемых сообщений очереди (${path})`
} }
} }
@ -400,8 +388,7 @@ exports.setQueueState = new Schema({
enum: [NINC_EXEC_CNT_NO, NINC_EXEC_CNT_YES], enum: [NINC_EXEC_CNT_NO, NINC_EXEC_CNT_YES],
required: false, required: false,
message: { message: {
type: path => type: path => `Флаг инкремента количества исполнений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Флаг инкремента количества исполнений (${path}) имеет некорректный тип данных (ожидалось - Number)`,
enum: path => `Значение флага инкремента количества исполнений (${path}) не поддерживается`, enum: path => `Значение флага инкремента количества исполнений (${path}) не поддерживается`,
required: path => `Не указан флаг икремента количества исполнений (${path})` required: path => `Не указан флаг икремента количества исполнений (${path})`
} }
@ -448,8 +435,7 @@ exports.setQueueMsg = new Schema({
use: { validateBuffer }, use: { validateBuffer },
required: true, required: true,
message: { message: {
validateBuffer: path => validateBuffer: path => `Данные сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
`Данные сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
required: path => `Не указаны данные сообщения очереди обмена (${path})` required: path => `Не указаны данные сообщения очереди обмена (${path})`
} }
} }
@ -471,8 +457,7 @@ exports.setQueueOptions = new Schema({
type: String, type: String,
required: true, required: true,
message: { message: {
validateBuffer: path => validateBuffer: path => `Парамметры сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
`Парамметры сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
required: path => `Не указаны параметры сообщения очереди обмена (${path})` required: path => `Не указаны параметры сообщения очереди обмена (${path})`
} }
} }
@ -507,8 +492,7 @@ exports.setQueueResp = new Schema({
use: { validateBuffer }, use: { validateBuffer },
required: true, required: true,
message: { message: {
validateBuffer: path => validateBuffer: path => `Данные ответа сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
`Данные ответа сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
required: path => `Не указаны данные ответа сообщения очереди обмена (${path})` required: path => `Не указаны данные ответа сообщения очереди обмена (${path})`
} }
}, },
@ -518,8 +502,7 @@ exports.setQueueResp = new Schema({
enum: [NIS_ORIGINAL_NO, NIS_ORIGINAL_YES], enum: [NIS_ORIGINAL_NO, NIS_ORIGINAL_YES],
required: true, required: true,
message: { message: {
type: path => type: path => `Признак передачи оригинала ответа (${path}) имеет некорректный тип данных (ожидалось - Number)`,
`Признак передачи оригинала ответа (${path}) имеет некорректный тип данных (ожидалось - Number)`,
enum: path => `Значение признака передачи оригинала ответа (${path}) не поддерживается`, enum: path => `Значение признака передачи оригинала ответа (${path}) не поддерживается`,
required: path => `Не указан признак передачи оригинала ответа (${path})` required: path => `Не указан признак передачи оригинала ответа (${path})`
} }
@ -542,8 +525,7 @@ exports.setQueueOptionsResp = new Schema({
type: String, type: String,
required: true, required: true,
message: { message: {
validateBuffer: path => validateBuffer: path => `Парамметры ответа на сообщение очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
`Парамметры ответа на сообщение очереди обмена (${path}) имеют некорректный тип данных (ожидалось - String)`,
required: path => `Не указаны параметры ответа на сообщение очереди обмена (${path})` required: path => `Не указаны параметры ответа на сообщение очереди обмена (${path})`
} }
} }
@ -565,8 +547,7 @@ exports.setQueueAppSrvResult = new Schema({
use: { validateBuffer }, use: { validateBuffer },
required: true, required: true,
message: { message: {
validateBuffer: path => validateBuffer: path => `Данные сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
`Данные сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
required: path => `Не указаны данные сообщения очереди обмена (${path})` required: path => `Не указаны данные сообщения очереди обмена (${path})`
} }
}, },
@ -575,8 +556,7 @@ exports.setQueueAppSrvResult = new Schema({
use: { validateBuffer }, use: { validateBuffer },
required: true, required: true,
message: { message: {
validateBuffer: path => validateBuffer: path => `Данные ответа сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
`Данные ответа сообщения очереди обмена (${path}) имеют некорректный тип данных (ожидалось - null или Buffer)`,
required: path => `Не указаны данные ответа сообщения очереди обмена (${path})` required: path => `Не указаны данные ответа сообщения очереди обмена (${path})`
} }
} }

View File

@ -20,6 +20,7 @@ const DT_DATE = oracledb.DB_TYPE_DATE; //Тип данных "Дата" БД
const DT_CLOB = oracledb.DB_TYPE_CLOB; //Тип данных "Текстовые данные" БД const DT_CLOB = oracledb.DB_TYPE_CLOB; //Тип данных "Текстовые данные" БД
const DT_BLOB = oracledb.DB_TYPE_BLOB; //Тип данных "Двоичные данные" БД const DT_BLOB = oracledb.DB_TYPE_BLOB; //Тип данных "Двоичные данные" БД
const DT_CURSOR = oracledb.CURSOR; //Тип данных "Курсор" БД const DT_CURSOR = oracledb.CURSOR; //Тип данных "Курсор" БД
const DT_VARCHAR_LENGTH = 32767; //Длина типа "Строка"
//------------ //------------
// Тело модуля // Тело модуля
@ -44,7 +45,8 @@ const makeStoredPrms = (inPrms, outPrms) => {
for (i in outPrms) { for (i in outPrms) {
prms[i] = { prms[i] = {
type: outPrms[i], type: outPrms[i],
dir: oracledb.BIND_OUT dir: oracledb.BIND_OUT,
...(outPrms[i] === DT_VARCHAR ? { maxSize: DT_VARCHAR_LENGTH } : {})
}; };
break; break;
} }
@ -122,46 +124,68 @@ const executeStored = async prms => {
if (outResult) return outResult; if (outResult) return outResult;
}; };
//Проверка допустимого количества воркеров //Проверка условий при запуске сервиса интеграции
const checkWorkers = async prms => { const checkAppStart = async prms => {
let workersData = await executeStored({ let res = await executeStored({
connection: prms.connection, connection: prms.connection,
sName: "PKG_EXS.UTL_LIC_CLNT_COUNT_GET", sName: "PKG_EXS.UTL_APPSRV_START_CHECK",
outPrms: { inPrms: {
LIC_CNT: DT_NUMBER NCONTROL_VERSION: prms.bControlSystemVersion ? 1 : 0,
SEXS_RELEASE_DATE: prms.sRelease,
NWORKERS: prms.nWorkers,
SEXSSRV: prms.sServerName,
SSESSION_APP_NAME: prms.sSessionAppName
}, },
isFunction: true outPrms: {
SERR_TEXT: DT_VARCHAR
},
isFunction: false
}); });
if (workersData.LIC_CNT === 0) { //Если есть ошибки запуска
throw new Error(`Не определено количество лицензий для приложения "ExchangeServer".`); if (res.SERR_TEXT) {
} throw new Error(res.SERR_TEXT);
if (prms.nMaxWorkers > workersData.LIC_CNT - 1) {
throw new Error(
`Недопустимое значение параметра "Количество одновременно обрабатываемых исходящих сообщений" ("outGoing.nMaxWorkers") файла конфигурации сервиса приложений ("config.js"). Максимальное количество одновременно обрабатываемых исходящих сообщений - ${
workersData.LIC_CNT - 1
}.`
);
} }
}; };
//Проверка соответствия релизов сервера приложений и системы //Инициализация сервера интеграции
const checkRelease = async prms => { const initServer = async prms => {
let releaseData = await executeStored({ let res = await executeStored({
connection: prms.connection, connection: prms.connection,
sName: "PKG_EXS.UTL_PRODUCT_RELEASE_GET", sName: "PKG_EXS.EXSSRV_INIT",
outPrms: { inPrms: {
DB_RELEASE: DT_VARCHAR SEXSSRV: prms.sServerName,
SIP: prms.sServerIP,
NWORKERS: prms.nMaxWorkers
}, },
isFunction: true outPrms: {
NEXSSRV: DT_NUMBER
},
isFunction: false
}); });
if (releaseData.DB_RELEASE !== prms.sRelease) { //Если рег. номер сервера интеграции не определен
throw new Error(`Версия сервера приложений (${prms.sRelease}) не соответствует версии системы (${releaseData.DB_RELEASE}).`); if (!res.NEXSSRV) {
throw new Error(`Ошибка считывания сервера интеграции с мнемокодом "${prms.sServerName}".`);
} }
//Возвращаем рег. номер сервера интеграции
return res.NEXSSRV;
};
//Очистка информации о сервере при закрытии сервиса
const clearServer = async prms => {
await executeStored({
connection: prms.connection,
sName: "PKG_EXS.EXSSRV_CLEAR",
inPrms: {
NEXSSRV: prms.nExsSrv
},
isFunction: false
});
}; };
//Подключение к БД //Подключение к БД
const connect = async prms => { const connect = async prms => {
try { try {
//Создаем пул подключения
let pool = await oracledb.createPool({ let pool = await oracledb.createPool({
user: prms.sUser, user: prms.sUser,
password: prms.sPassword, password: prms.sPassword,
@ -171,21 +195,21 @@ const connect = async prms => {
poolMax: prms.nPoolMax ? prms.nPoolMax : 4, poolMax: prms.nPoolMax ? prms.nPoolMax : 4,
poolIncrement: prms.nPoolIncrement ? prms.nPoolIncrement : 0, poolIncrement: prms.nPoolIncrement ? prms.nPoolIncrement : 0,
sessionCallback: (connection, requestedTag, callback) => { sessionCallback: (connection, requestedTag, callback) => {
if (prms.sSessionAppName) connection.module = prms.sSessionAppName; //Устанавливаем схему
connection.execute(`ALTER SESSION SET CURRENT_SCHEMA=${prms.sSchema}`).then( connection
r => { .execute(`ALTER SESSION SET CURRENT_SCHEMA=${prms.sSchema}`)
.then(r => {
//Устанавливаем модуль сессии
connection.execute(`begin PKG_EXS.UTL_MODULE_SET(SEXSSRV => '${prms.exsSrv.sServerName}'); end;`);
})
.then(r => {
callback(null, connection); callback(null, connection);
}, })
e => { .catch(e => {
callback(e, null); callback(e, null);
} });
);
} }
}); });
if (prms.bControlSystemVersion) {
await checkRelease({ sRelease: prms.sRelease, connection: pool });
}
await checkWorkers({ nMaxWorkers: prms.nMaxWorkers, connection: pool });
return pool; return pool;
} catch (e) { } catch (e) {
throw new Error(e.message); throw new Error(e.message);
@ -195,6 +219,7 @@ const connect = async prms => {
//Отключение от БД //Отключение от БД
const disconnect = async prms => { const disconnect = async prms => {
try { try {
//Отключаем от базы данных
await prms.connection.close(NPOOL_DRAIN_TIME); await prms.connection.close(NPOOL_DRAIN_TIME);
return; return;
} catch (e) { } catch (e) {
@ -207,6 +232,9 @@ const getServices = async prms => {
let servicesData = await executeStored({ let servicesData = await executeStored({
connection: prms.connection, connection: prms.connection,
sName: "PKG_EXS.SERVICES_GET", sName: "PKG_EXS.SERVICES_GET",
inPrms: {
NEXSSRV: prms.nExsSrv
},
outPrms: { outPrms: {
RCSERVICES: DT_CURSOR RCSERVICES: DT_CURSOR
} }
@ -315,7 +343,8 @@ const log = async prms => {
SMSG: prms.sMsg, SMSG: prms.sMsg,
NEXSSERVICE: prms.nServiceId, NEXSSERVICE: prms.nServiceId,
NEXSSERVICEFN: prms.nServiceFnId, NEXSSERVICEFN: prms.nServiceFnId,
NEXSQUEUE: prms.nQueueId NEXSQUEUE: prms.nQueueId,
NEXSSRV: prms.nExsSrv
}, },
outPrms: { RCLOG: DT_CURSOR } outPrms: { RCLOG: DT_CURSOR }
}); });
@ -361,7 +390,8 @@ const getQueueOutgoing = async prms => {
connection: prms.connection, connection: prms.connection,
sName: "PKG_EXS.QUEUE_SRV_TYPE_SEND_GET", sName: "PKG_EXS.QUEUE_SRV_TYPE_SEND_GET",
inPrms: { inPrms: {
NPORTION_SIZE: prms.nPortionSize NPORTION_SIZE: prms.nPortionSize,
NEXSSRV: prms.nExsSrv
}, },
outPrms: { RCQUEUES: DT_CURSOR } outPrms: { RCQUEUES: DT_CURSOR }
}); });
@ -492,6 +522,9 @@ exports.DT_CLOB = DT_CLOB;
exports.DT_BLOB = DT_BLOB; exports.DT_BLOB = DT_BLOB;
exports.DT_CURSOR = DT_CURSOR; exports.DT_CURSOR = DT_CURSOR;
exports.executeStored = executeStored; exports.executeStored = executeStored;
exports.checkAppStart = checkAppStart;
exports.initServer = initServer;
exports.clearServer = clearServer;
exports.connect = connect; exports.connect = connect;
exports.disconnect = disconnect; exports.disconnect = disconnect;
exports.getServices = getServices; exports.getServices = getServices;

View File

@ -130,44 +130,65 @@ const executeStored = async prms => {
if (outResult) return outResult; if (outResult) return outResult;
}; };
//Проверка допустимого количества воркеров //Проверка условий при запуске сервиса интеграции
const checkWorkers = async prms => { const checkAppStart = async prms => {
let workersData = await executeStored({ let res = await executeStored({
connection: prms.connection, connection: prms.connection,
sName: "PKG_EXS$UTL_LIC_CLNT_COUNT_GET", sName: "PKG_EXS$UTL_APPSRV_START_CHECK",
inPrms: {
NCONTROL_VERSION: prms.bControlSystemVersion ? 1 : 0,
SEXS_RELEASE_DATE: prms.sRelease,
NWORKERS: prms.nWorkers,
SEXSSRV: prms.sServerName !== "" ? prms.sServerName : null,
SSESSION_APP_NAME: prms.sSessionAppName
},
outPrms: { outPrms: {
LIC_CNT: DT_NUMBER SERR_TEXT: DT_VARCHAR
} }
}); });
if (workersData.LIC_CNT === 0) { //Если есть ошибки запуска
throw new Error(`Не определено количество лицензий для приложения "ExchangeServer".`); if (res.SERR_TEXT) {
} throw new Error(res.SERR_TEXT);
if (prms.nMaxWorkers > workersData.LIC_CNT - 1) {
throw new Error(
`Недопустимое значение параметра "Количество одновременно обрабатываемых исходящих сообщений" ("outGoing.nMaxWorkers") файла конфигурации сервиса приложений ("config.js"). Максимальное количество одновременно обрабатываемых исходящих сообщений - ${
workersData.LIC_CNT - 1
}.`
);
} }
}; };
//Проверка соответствия релизов сервера приложений и системы //Инициализация сервера интеграции
const checkRelease = async prms => { const initServer = async prms => {
let releaseData = await executeStored({ let res = await executeStored({
connection: prms.connection, connection: prms.connection,
sName: "PKG_EXS$UTL_PRODUCT_RELEASE_GET", sName: "PKG_EXS$EXSSRV_INIT",
inPrms: {
SEXSSRV: prms.sServerName,
SIP: prms.sServerIP,
NWORKERS: prms.nMaxWorkers
},
outPrms: { outPrms: {
DB_RELEASE: DT_VARCHAR NEXSSRV: DT_NUMBER
} }
}); });
if (releaseData.DB_RELEASE !== prms.sRelease) { //Если рег. номер сервера интеграции потерялся
throw new Error(`Версия сервера приложений (${prms.sRelease}) не соответствует версии системы (${releaseData.DB_RELEASE}).`); if (!res.NEXSSRV) {
throw new Error(`Ошибка считывания сервера интеграции с мнемокодом "${prms.sServerName}".`);
} }
//Возвращаем рег. номер сервера интеграции
return res.NEXSSRV;
};
//Очистка информации о сервере при закрытии сервиса
const clearServer = async prms => {
await executeStored({
connection: prms.connection,
sName: "PKG_EXS$EXSSRV_CLEAR",
inPrms: {
NEXSSRV: prms.nExsSrv
}
});
}; };
//Подключение к БД //Подключение к БД
const connect = async prms => { const connect = async prms => {
try { try {
//Создаем пул подключения
let pool = new pg.Pool({ let pool = new pg.Pool({
connectionString: `postgres://${prms.sUser}:${prms.sPassword}@${prms.sConnectString}`, connectionString: `postgres://${prms.sUser}:${prms.sPassword}@${prms.sConnectString}`,
connectionTimeoutMillis: 600000, connectionTimeoutMillis: 600000,
@ -175,12 +196,11 @@ const connect = async prms => {
max: prms.nPoolMax ? prms.nPoolMax : 4 max: prms.nPoolMax ? prms.nPoolMax : 4
}); });
pool.on("acquire", async client => { pool.on("acquire", async client => {
//Устанавливаем схему
await client.query(`select ALTER_SESSION_SET_SCHEMA($1);`, [prms.sSchema]); await client.query(`select ALTER_SESSION_SET_SCHEMA($1);`, [prms.sSchema]);
//Устанавливаем модуль сессии
await client.query(`select PKG_EXS$UTL_MODULE_SET($1);`, [prms.exsSrv.sServerName]);
}); });
if (prms.bControlSystemVersion) {
await checkRelease({ sRelease: prms.sRelease, connection: pool });
}
await checkWorkers({ nMaxWorkers: prms.nMaxWorkers, connection: pool });
return pool; return pool;
} catch (e) { } catch (e) {
throw new Error(e.message); throw new Error(e.message);
@ -201,6 +221,9 @@ const getServices = async prms => {
let servicesData = await executeStored({ let servicesData = await executeStored({
connection: prms.connection, connection: prms.connection,
sName: "PKG_EXS$SERVICES_GET", sName: "PKG_EXS$SERVICES_GET",
inPrms: {
NEXSSRV: prms.nExsSrv
},
outPrms: { outPrms: {
RCSERVICES: DT_CURSOR RCSERVICES: DT_CURSOR
} }
@ -308,7 +331,8 @@ const log = async prms => {
SMSG: prms.sMsg, SMSG: prms.sMsg,
NEXSSERVICE: prms.nServiceId, NEXSSERVICE: prms.nServiceId,
NEXSSERVICEFN: prms.nServiceFnId, NEXSSERVICEFN: prms.nServiceFnId,
NEXSQUEUE: prms.nQueueId NEXSQUEUE: prms.nQueueId,
NEXSSRV: prms.nExsSrv
}, },
outPrms: { RCLOG: DT_CURSOR } outPrms: { RCLOG: DT_CURSOR }
}); });
@ -354,7 +378,8 @@ const getQueueOutgoing = async prms => {
connection: prms.connection, connection: prms.connection,
sName: "PKG_EXS$QUEUE_SRV_TYPE_SEND_GET", sName: "PKG_EXS$QUEUE_SRV_TYPE_SEND_GET",
inPrms: { inPrms: {
NPORTION_SIZE: prms.nPortionSize NPORTION_SIZE: prms.nPortionSize,
NEXSSRV: prms.nExsSrv
}, },
outPrms: { RCQUEUES: DT_CURSOR } outPrms: { RCQUEUES: DT_CURSOR }
}); });
@ -485,6 +510,9 @@ exports.DT_CLOB = DT_CLOB;
exports.DT_BLOB = DT_BLOB; exports.DT_BLOB = DT_BLOB;
exports.DT_CURSOR = DT_CURSOR; exports.DT_CURSOR = DT_CURSOR;
exports.executeStored = executeStored; exports.executeStored = executeStored;
exports.checkAppStart = checkAppStart;
exports.initServer = initServer;
exports.clearServer = clearServer;
exports.connect = connect; exports.connect = connect;
exports.disconnect = disconnect; exports.disconnect = disconnect;
exports.getServices = getServices; exports.getServices = getServices;