import { LoggerFactory, LogLevel, LogTimestampFormat } from '@rsdk/logging'; import type { TransportMultiOptions } from 'pino'; import pino from 'pino'; /** * Регресс на баг, пойманный реальным запуском: applyInstrumentations пересоздавал * только что созданный worker-транспорт и синхронно звал .end(), который у * медленно закрывающихся транспортов (OTEL) висел 10с и ронял процесс. Теперь * воркер переиспользуется, пока его конфиг не сменился. */ interface FakeStream { write: jest.Mock; on: jest.Mock; end: jest.Mock; flush: jest.Mock; flushSync: jest.Mock; unref: jest.Mock; writable: boolean; } function fakeStream(): FakeStream { return { write: jest.fn(), on: jest.fn(), end: jest.fn(), flush: jest.fn((cb?: () => void) => cb?.()), flushSync: jest.fn(), unref: jest.fn(), writable: true, }; } const base = { level: LogLevel.info, redact: [] as string[], timestampFormat: LogTimestampFormat.isoTime, }; function transport(dest: number): TransportMultiOptions { return { targets: [ { target: 'pino/file', options: { destination: dest }, level: 'info' }, ], }; } describe('LoggerFactory — жизненный цикл worker-транспорта', () => { let transportSpy: jest.SpyInstance; beforeEach(() => { transportSpy = jest .spyOn(pino, 'transport') .mockImplementation(() => fakeStream() as any); }); afterEach(() => { jest.restoreAllMocks(); }); it('переиспользует воркер на applyInstrumentations (не пересоздаёт)', () => { const t = transport(1); LoggerFactory.reconfigure({ ...base, transport: t }); expect(transportSpy).toHaveBeenCalledTimes(1); LoggerFactory.applyInstrumentations(() => {}); LoggerFactory.applyInstrumentations(() => {}); // воркер тот же — pino.transport больше не вызывался expect(transportSpy).toHaveBeenCalledTimes(1); }); it('пересоздаёт воркер при смене конфига транспорта', () => { LoggerFactory.reconfigure({ ...base, transport: transport(1) }); LoggerFactory.reconfigure({ ...base, transport: transport(1) }); // новый объект expect(transportSpy).toHaveBeenCalledTimes(2); }); it('закрывает воркер при переключении на stream', () => { LoggerFactory.reconfigure({ ...base, transport: transport(1) }); const created = transportSpy.mock.results[0].value; LoggerFactory.reconfigure({ ...base, stream: { write() {}, writable: true } as any, }); expect(created.end).toHaveBeenCalled(); }); });