P8-ExchangeService/core/out_queue_processor2.js

382 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Сервис интеграции ПП Парус 8 с WEB API
Модуль ядра: обработчик исходящего сообщения
*/
//----------------------
// Подключение библиотек
//----------------------
require("module-alias/register"); //Поддержка псевонимов при подключении модулей
const _ = require("lodash"); //Работа с массивами и коллекциями
const lg = require("./logger"); //Протоколирование работы
const db = require("./db_connector"); //Взаимодействие с БД
const { makeModuleFullPath, validateObject } = require("./utils"); //Вспомогательные функции
const { ServerError } = require("./server_errors"); //Типовая ошибка
const objOutQueueProcessorSchema = require("../models/obj_out_queue_processor"); //Схема валидации сообщений обмена с бработчиком очереди исходящих сообщений
const prmsOutQueueProcessorSchema = require("../models/prms_out_queue_processor"); //Схема валидации параметров функций модуля
const objQueueSchema = require("../models/obj_queue"); //Схемы валидации сообщения очереди
const {
SERR_UNEXPECTED,
SERR_MODULES_BAD_INTERFACE,
SERR_OBJECT_BAD_INTERFACE,
SERR_MODULES_NO_MODULE_SPECIFIED
} = require("./constants"); //Глобальные константы
const { NINC_EXEC_CNT_YES, NINC_EXEC_CNT_NO } = require("../models/prms_db_connector"); //Схемы валидации параметров функций модуля взаимодействия с БД
//----------
// Константы
//----------
//--------------------------
// Глобальные идентификаторы
//--------------------------
let dbConn = null; //Подключение к БД
let logger = null; //Протоколирование работы
//------------
// Тело модуля
//------------
//Отправка родительскому процессу ошибки обработки сообщения сервером приложений
const sendErrorResult = sMessage => {
process.send({
sExecResult: "ERR",
sExecMsg: sMessage
});
};
//Отправка родительскому процессу успеха обработки сообщения сервером приложений
const sendOKResult = () => {
process.send({
sExecResult: "OK",
sExecMsg: null
});
};
//Запись в файл !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! УБРАТЬ!!!!!!!!!!!!!!!!!
const writeToFile = queue => {
return new Promise((resolve, reject) => {
const fs = require("fs");
fs.writeFile("c:/repos/temp/" + queue.nId, queue.blMsg, err => {
if (err) {
reject(new ServerError(SERR_UNEXPECTED, `Ошибка отработки сообщения ${prms.queue.nId}`));
} else {
resolve();
}
});
});
};
//Запуск обработки сообщения сервером приложений
const appProcess = async prms => {
//Обработанное сообщение
let newQueue = null;
//Обрабатываем
try {
//Фиксируем начало исполнения сервером приложений - в статусе сообщения
newQueue = await dbConn.setQueueState({
nQueueId: prms.queue.nId,
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_APP
});
//Скажем что начали обработку
await logger.info(
`Обрабатываю исходящее сообщение сервером приложений: ${prms.queue.nId}, ${prms.queue.sInDate}, ${
prms.queue.sServiceFnCode
}, ${prms.queue.sExecState}, попытка исполнения - ${prms.queue.nExecCnt + 1}`,
{ nQueueId: prms.queue.nId }
);
if (prms.queue.blMsg) {
await writeToFile(prms.queue);
let sMsg = prms.queue.blMsg.toString() + " MODIFICATION FOR " + prms.queue.nId;
//Фиксируем успех исполнения
newQueue = await dbConn.setQueueAppSrvResult({
nQueueId: prms.queue.nId,
blMsg: new Buffer(sMsg),
blResp: new Buffer("REPLAY ON " + prms.queue.nId)
});
//Фиксируем успешное исполнение сервером приложений - в статусе сообщения
newQueue = await dbConn.setQueueState({
nQueueId: prms.queue.nId,
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_APP_OK
});
//Фиксируем успешное исполнение сервером приложений - в протоколе работы сервиса
await logger.info(`Исходящее сообщение ${prms.queue.nId} успешно отработано сервером приложений`, {
nQueueId: prms.queue.nId
});
} else {
throw new ServerError(
SERR_UNEXPECTED,
`Ошибка отработки сообщения ${prms.queue.nId}: нет данных для обработки`
);
}
} catch (e) {
//Сформируем текст ошибки
let sErr = `${SERR_UNEXPECTED}: ${e.message}`;
if (e instanceof ServerError) sErr = `${e.sCode}: ${e.sMessage}`;
//Фиксируем ошибку обработки сервером приложений - в статусе сообщения
newQueue = await dbConn.setQueueState({
nQueueId: prms.queue.nId,
sExecMsg: sErr,
nIncExecCnt: NINC_EXEC_CNT_YES,
nExecState:
prms.queue.nExecCnt + 1 < prms.queue.nRetryAttempts
? objQueueSchema.NQUEUE_EXEC_STATE_APP_ERR
: objQueueSchema.NQUEUE_EXEC_STATE_ERR
});
//Фиксируем ошибку обработки сервером приложений - в протоколе работы сервиса
await logger.error(`Ошибка обработки исходящего сообщения ${prms.queue.nId} сервером приложений: ${sErr}`, {
nQueueId: prms.queue.nId
});
}
//Возвращаем результат
return newQueue;
};
//Запуск обработки сообщения сервером БД
const dbProcess = async prms => {
//Проверяем структуру переданного объекта для старта
//let sCheckResult = validateObject(
// prms,
// prmsOutQueueSchema.dbProcess,
// "Параметры функции запуска обработки ообщения сервером БД"
//);
//Если структура объекта в норме
//if (!sCheckResult) {
//Обрабатываем
try {
//Фиксируем начало исполнения сервером БД - в статусе сообщения
await dbConn.setQueueState({
nQueueId: prms.queue.nId,
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_DB
});
//Скажем что начали обработку
await logger.info(
`Обрабатываю исходящее сообщение сервером БД: ${prms.queue.nId}, ${prms.queue.sInDate}, ${
prms.queue.sServiceFnCode
}, ${prms.queue.sExecState}, попытка исполнения - ${prms.queue.nExecCnt + 1}`,
{ nQueueId: prms.queue.nId }
);
//Вызов обработчика БД
await dbConn.execQueueDBPrc({ nQueueId: prms.queue.nId });
//Фиксируем успешное исполнение сервером БД - в статусе сообщения
await dbConn.setQueueState({
nQueueId: prms.queue.nId,
nIncExecCnt: prms.queue.nExecCnt == 0 ? NINC_EXEC_CNT_YES : NINC_EXEC_CNT_NO,
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_OK
});
//Фиксируем успешное исполнение сервером БД - в протоколе работы сервиса
await logger.info(`Исходящее сообщение ${prms.queue.nId} успешно отработано сервером БД`, {
nQueueId: prms.queue.nId
});
} catch (e) {
//Сформируем текст ошибки
let sErr = `${SERR_UNEXPECTED}: ${e.message}`;
if (e instanceof ServerError) sErr = `${e.sCode}: ${e.sMessage}`;
//Фиксируем ошибку обработки сервером БД - в статусе сообщения
await dbConn.setQueueState({
nQueueId: prms.queue.nId,
sExecMsg: sErr,
nIncExecCnt: NINC_EXEC_CNT_YES,
nExecState:
prms.queue.nExecCnt + 1 < prms.queue.nRetryAttempts
? objQueueSchema.NQUEUE_EXEC_STATE_DB_ERR
: objQueueSchema.NQUEUE_EXEC_STATE_ERR
});
//Фиксируем ошибку обработки сервером БД - в протоколе работы сервиса
await logger.error(`Ошибка обработки исходящего сообщения ${prms.queue.nId} сервером БД: ${sErr}`, {
nQueueId: prms.queue.nId
});
}
//} else {
// throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult);
//}
};
//Протоколирование предупреждения о ненадлежащем статусе сообщения
const warnBadStateForProcess = async prms => {
//Предупредим о неверном статусе сообщения (такие сюда попадать не должны)
await logger.warn(`Cообщение ${prms.queue.nId} в статусе ${prms.queue.sExecState} попало в очередь обработчика`, {
nQueueId: prms.queue.nId
});
};
//Обработка задачи
const processTask = async prms => {
//Проверяем параметры
/*
let sCheckResult = validateObject(
prms,
prmsOutQueueProcessorSchema.processTask,
"Параметры функции обработки задачи"
);
*/
//Если параметры в норме
//if (!sCheckResult) {
let q = null;
try {
//Создаём подключение к БД
dbConn = new db.DBConnector({ connectSettings: prms.task.connectSettings });
//Создаём логгер для протоколирования работы
logger = new lg.Logger();
//Подключим логгер к БД (и отключим когда надо)
dbConn.on(db.SEVT_DB_CONNECTOR_CONNECTED, connection => {
logger.setDBConnector(dbConn, true);
});
dbConn.on(db.SEVT_DB_CONNECTOR_DISCONNECTED, () => {
logger.removeDBConnector();
});
//Подключаемся к БД
await dbConn.connect();
//Считываем запись очереди
q = await dbConn.getQueue({ nQueueId: prms.task.nQueueId });
//Далее работаем от статуса считанной записи
switch (q.nExecState) {
//Поставлено в очередь
case objQueueSchema.NQUEUE_EXEC_STATE_INQUEUE: {
//Запускаем обработку сервером приложений
let res = await appProcess({ queue: q });
//И если она успешно завершилась - обработку сервоером БД
if (res.nExecState == objQueueSchema.NQUEUE_EXEC_STATE_APP_OK) await dbProcess({ queue: res });
break;
}
//Обрабатывается сервером приложений
case objQueueSchema.NQUEUE_EXEC_STATE_APP: {
//Ничего не делаем, но предупредим что так быть не должно
await warnBadStateForProcess({ queue: q });
break;
}
//Ошибка обработки сервером приложений
case objQueueSchema.NQUEUE_EXEC_STATE_APP_ERR: {
//Если ещё есть попытки отработки
if (q.nExecCnt < q.nRetryAttempts) {
//Снова запускаем обработку сервером приложений
let res = await appProcess({ queue: q });
//И если она успешно завершилась - обработку сервоером БД
if (res.nExecState == objQueueSchema.NQUEUE_EXEC_STATE_APP_OK) await dbProcess({ queue: res });
} else {
//Попыток нет - финализируем обработку
await dbConn.setQueueState({
nQueueId: q.nId,
sExecMsg: q.sExecMsg,
nIncExecCnt: q.nExecCnt == 0 ? NINC_EXEC_CNT_YES : NINC_EXEC_CNT_NO,
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_ERR
});
}
break;
}
//Успешно обработано сервером приложений
case objQueueSchema.NQUEUE_EXEC_STATE_APP_OK: {
//Запускаем обработку в БД
await dbProcess({ queue: q });
break;
}
//Обрабатывается в БД
case objQueueSchema.NQUEUE_EXEC_STATE_DB: {
//Ничего не делаем, но предупредим что так быть не должно
await warnBadStateForProcess({ queue: q });
break;
}
//Ошибка обработки в БД
case objQueueSchema.NQUEUE_EXEC_STATE_DB_ERR: {
//Если ещё есть попытки отработки
if (q.nExecCnt < q.nRetryAttempts) {
//Снова запускаем обработку сервером БД
await dbProcess({ queue: q });
} else {
//Попыток нет - финализируем обработку
await dbConn.setQueueState({
nQueueId: q.nId,
sExecMsg: q.sExecMsg,
nIncExecCnt: q.nExecCnt == 0 ? NINC_EXEC_CNT_YES : NINC_EXEC_CNT_NO,
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_ERR
});
}
break;
}
//Успешно обработано в БД
case objQueueSchema.NQUEUE_EXEC_STATE_DB_OK: {
//Финализируем
await dbConn.setQueueState({
nQueueId: q.nId,
sExecMsg: null,
nIncExecCnt: q.nExecCnt == 0 ? NINC_EXEC_CNT_YES : NINC_EXEC_CNT_NO,
nExecState: objQueueSchema.NQUEUE_EXEC_STATE_OK
});
break;
}
//Обработано с ошибками
case objQueueSchema.NQUEUE_EXEC_STATE_ERR: {
//Ничего не делаем, но предупредим что так быть не должно
await warnBadStateForProcess({ queue: q });
break;
}
//Обработано успешно
case objQueueSchema.NQUEUE_EXEC_STATE_OK: {
//Ничего не делаем, но предупредим что так быть не должно
await warnBadStateForProcess({ queue: q });
break;
}
default: {
//Ничего не делаем
break;
}
}
//Отключаемся от БД
if (dbConn) await dbConn.disconnect();
//Отправляем успех
sendOKResult();
} catch (e) {
//Отключаемся от БД
if (dbConn) await dbConn.disconnect();
//Отправляем ошибку
let sErr = `${SERR_UNEXPECTED}: ${e.message}`;
if (e instanceof ServerError) sErr = `${e.sCode}: ${e.sMessage}`;
sendErrorResult(sErr);
}
//Отправим родителю информацию о том, что закончили обработку
//} else {
// sendErrorResult({ sMessage: sCheckResult });
//}
};
//---------------------------------
// Управление процессом обработчика
//---------------------------------
//Перехват CTRL + C (останов процесса)
process.on("SIGINT", () => {});
//Перехват CTRL + \ (останов процесса)
process.on("SIGQUIT", () => {});
//Перехват мягкого останова процесса
process.on("SIGTERM", () => {});
//Перехват ошибок
process.on("uncaughtException", e => {
//Отправляем ошибку родительскому процессу
sendErrorResult(e.message);
});
//Приём сообщений
process.on("message", task => {
//Проверяем структуру переданного сообщения
/*
let sCheckResult = validateObject(
task,
objOutQueueProcessorSchema.OutQueueProcessorTask,
"Задача обработчика очереди исходящих сообщений"
);
*/
//Если структура объекта в норме
//if (!sCheckResult) {
//Запускаем обработку
processTask({ task });
//} else {
// throw new ServerError(SERR_OBJECT_BAD_INTERFACE, sCheckResult);
//}
});