From 85658225a3c043092524cfa90cf7bc5842cab490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D0=BE=D0=B2=20=D0=90=D1=80=D1=82?= =?UTF-8?q?=D0=B5=D0=BC?= Date: Wed, 8 Jul 2026 15:55:21 +0300 Subject: [PATCH] =?UTF-8?q?BUR-68=20=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D0=BA=D0=BE=D0=B4.=20?= =?UTF-8?q?=D0=9D=D0=B0=D1=88=D0=B5=D0=BB=20=D0=BF=D1=80=D0=B8=D1=87=D0=B8?= =?UTF-8?q?=D0=BD=D1=83=20=D0=BD=D0=B5=D0=BE=D1=82=D0=BB=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B8=D0=B2=D0=B0=D0=B5=D0=BC=D0=B3=D0=BE=20=D1=8D=D0=BA=D1=81?= =?UTF-8?q?=D0=BF=D0=B5=D1=88=D0=B5=D0=BD=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/handlers/edge5-modbus-v3.ts | 7 +++- app/src/index.ts | 1 - app/src/process-errors.ts | 57 ----------------------------- app/src/router.ts | 48 ++++++++++++++++++++---- 4 files changed, 46 insertions(+), 67 deletions(-) delete mode 100644 app/src/process-errors.ts diff --git a/app/src/handlers/edge5-modbus-v3.ts b/app/src/handlers/edge5-modbus-v3.ts index dd9567a..bf72661 100644 --- a/app/src/handlers/edge5-modbus-v3.ts +++ b/app/src/handlers/edge5-modbus-v3.ts @@ -89,7 +89,12 @@ async function postMetrics(metrics: Edge5ModbusV3Metric[]): Promise { throw new Error(text || `${response.status} ${response.statusText}`) } - void postDemoCloudIngest(metric); // для демо-системы + const demoResponse = await postDemoCloudIngest(metric); // для демо-системы + + if (!demoResponse.ok) { + const text = await demoResponse.text() + throw new Error(text || `${demoResponse.status} ${demoResponse.statusText}`) + } } catch (error) { const message = error instanceof Error ? error.message : String(error) diff --git a/app/src/index.ts b/app/src/index.ts index 1cd4f4e..9fbd394 100644 --- a/app/src/index.ts +++ b/app/src/index.ts @@ -1,4 +1,3 @@ -import './process-errors.js' import './handlers/index.js' import './http/server.js' import './mqtt.js' diff --git a/app/src/process-errors.ts b/app/src/process-errors.ts deleted file mode 100644 index 4b33394..0000000 --- a/app/src/process-errors.ts +++ /dev/null @@ -1,57 +0,0 @@ -type ErrorWithCause = Error & { - cause?: unknown -} - -type NodeError = Error & { - code?: string - address?: string - port?: number -} - -// Undici кладёт системную ошибку соединения внутрь error.cause. -function getFetchCause(error: unknown): NodeError | null { - if (!(error instanceof Error)) { - return null - } - - const cause = (error as ErrorWithCause).cause - return cause instanceof Error ? (cause as NodeError) : null -} - -// Обрабатываем только подсвеченный кейс: backend отказал в TCP-соединении. -function isFetchConnectionRefused(error: unknown): boolean { - if (!(error instanceof Error)) { - return false - } - - const cause = getFetchCause(error) - return error.message === 'fetch failed' && cause?.code === 'ECONNREFUSED' -} - -// Логируем короткую диагностическую форму без огромного stack trace. -function formatFetchError(error: unknown): object { - if (!(error instanceof Error)) { - return { message: String(error) } - } - - const cause = getFetchCause(error) - return { - message: error.message, - cause: cause?.message, - code: cause?.code, - address: cause?.address, - port: cause?.port, - } -} - -// Последний рубеж защиты для fire-and-forget fetch-запросов. -// Если backend недоступен, Node.js 22 может превратить незахваченный -// fetch failed / ECONNREFUSED в падение всего процесса mqtt-worker. -process.on('unhandledRejection', (error) => { - if (isFetchConnectionRefused(error)) { - console.error('process.unhandled_fetch_refused', formatFetchError(error)) - return - } - - console.error('process.unhandled_rejection', error) -}) diff --git a/app/src/router.ts b/app/src/router.ts index 2f1c502..27b20a6 100644 --- a/app/src/router.ts +++ b/app/src/router.ts @@ -1,19 +1,51 @@ import { resolveHandler } from './registry.js' +type ErrorWithCause = Error & { + cause?: unknown +} + +type NodeError = Error & { + code?: string + address?: string + port?: number +} + +function getErrorCause(error: Error): NodeError | null { + const cause = (error as ErrorWithCause).cause + return cause instanceof Error ? (cause as NodeError) : null +} + +function formatHandlerError(error: unknown): object { + if (!(error instanceof Error)) { + return { message: String(error) } + } + + const cause = getErrorCause(error) + + return { + message: error.message, + cause: cause?.message, + code: cause?.code, + address: cause?.address, + port: cause?.port, + stack: error.stack, + } +} + export async function routeMessage( topic: string, payload: Buffer, ): Promise { - const handler = resolveHandler(topic) - - if (!handler) { - console.warn('mqtt.unhandled_topic', { topic }) - return - } - try { + const handler = resolveHandler(topic) + + if (!handler) { + console.warn('mqtt.unhandled_topic', { topic }) + return + } + await handler(topic, payload) } catch (err) { - console.error('mqtt.handler_error', { topic, err }) + console.error('mqtt.handler_error', { topic, error: formatHandlerError(err) }) } }