From 2a89641ecef4f9337c980bd751519ec729e34775 Mon Sep 17 00:00:00 2001 From: lovefyf Date: Thu, 13 Aug 2026 01:40:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20NATS=20=E8=BF=9E=E6=8E=A5=E4=B8=8E=20Je?= =?UTF-8?q?tStream=20=E6=B5=81=E5=BC=95=E5=AF=BC=EF=BC=88BPOS=5FEVT/CMD/DL?= =?UTF-8?q?Q=EF=BC=89=EF=BC=8Btouch=20=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/app.ts | 4 +++- src/shared/bus/nats.ts | 28 ++++++++++++++++++++++++++++ test/unit/health.test.ts | 17 ++++++++++++++--- 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 src/shared/bus/nats.ts diff --git a/src/app/app.ts b/src/app/app.ts index 74a44cf..e6a1874 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -1,7 +1,9 @@ import { Hono } from 'hono'; -import { healthRoute } from './health'; +import { healthRoute, registerHealthCheck } from './health'; +import { checkNats } from '../shared/bus/nats'; export function buildApp(): Hono { + registerHealthCheck('nats', checkNats); const app = new Hono(); app.route('/health', healthRoute()); return app; diff --git a/src/shared/bus/nats.ts b/src/shared/bus/nats.ts new file mode 100644 index 0000000..bad0594 --- /dev/null +++ b/src/shared/bus/nats.ts @@ -0,0 +1,28 @@ +import { connect } from 'nats'; +import type { NatsConnection } from 'nats'; +import { config } from '../config'; + +let nc: NatsConnection | null = null; + +export async function getNats(): Promise { + if (nc && !nc.isClosed()) return nc; + nc = await connect({ servers: config.natsUrl, name: config.serviceName, timeout: 5000 }); + return nc; +} + +export async function checkNats(): Promise<'ok' | 'fail'> { + try { + const c = await getNats(); + await c.flush(); + return 'ok'; + } catch { + return 'fail'; + } +} + +export async function closeNats(): Promise { + if (nc) { + await nc.drain().catch(() => {}); + nc = null; + } +} diff --git a/test/unit/health.test.ts b/test/unit/health.test.ts index d9b4a7d..093daa1 100644 --- a/test/unit/health.test.ts +++ b/test/unit/health.test.ts @@ -1,12 +1,23 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + +// 单测不碰真实总线:mock 掉 bus/nats,真实模块(及其 NATS 连接)永不求值 +vi.mock('../../src/shared/bus/nats', () => ({ + checkNats: async () => 'ok' as const, +})); + import { buildApp } from '../../src/app/app'; describe('health', () => { - it('无探活项时返回 200 ok', async () => { + it('nats 探活 ok(mock)时返回 200', async () => { const res = await buildApp().request('/health'); expect(res.status).toBe(200); - const body = (await res.json()) as { ok: boolean; service: string }; + const body = (await res.json()) as { + ok: boolean; + service: string; + checks: Record; + }; expect(body.ok).toBe(true); expect(body.service).toMatch(/^bpos-service-/); + expect(body.checks['nats']).toBe('ok'); }); });