feat: NATS 连接与 JetStream 流引导(BPOS_EVT/CMD/DLQ)+touch 发布
This commit is contained in:
+3
-1
@@ -1,7 +1,9 @@
|
|||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { healthRoute } from './health';
|
import { healthRoute, registerHealthCheck } from './health';
|
||||||
|
import { checkNats } from '../shared/bus/nats';
|
||||||
|
|
||||||
export function buildApp(): Hono {
|
export function buildApp(): Hono {
|
||||||
|
registerHealthCheck('nats', checkNats);
|
||||||
const app = new Hono();
|
const app = new Hono();
|
||||||
app.route('/health', healthRoute());
|
app.route('/health', healthRoute());
|
||||||
return app;
|
return app;
|
||||||
|
|||||||
@@ -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<NatsConnection> {
|
||||||
|
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<void> {
|
||||||
|
if (nc) {
|
||||||
|
await nc.drain().catch(() => {});
|
||||||
|
nc = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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';
|
import { buildApp } from '../../src/app/app';
|
||||||
|
|
||||||
describe('health', () => {
|
describe('health', () => {
|
||||||
it('无探活项时返回 200 ok', async () => {
|
it('nats 探活 ok(mock)时返回 200', async () => {
|
||||||
const res = await buildApp().request('/health');
|
const res = await buildApp().request('/health');
|
||||||
expect(res.status).toBe(200);
|
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<string, string>;
|
||||||
|
};
|
||||||
expect(body.ok).toBe(true);
|
expect(body.ok).toBe(true);
|
||||||
expect(body.service).toMatch(/^bpos-service-/);
|
expect(body.service).toMatch(/^bpos-service-/);
|
||||||
|
expect(body.checks['nats']).toBe('ok');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user