Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions apps/backend/middleware/legacy/mirror.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ import { MirrorCommandQueue } from './commandqueue.mirror';

import { PostHog } from 'posthog-node';

let postHogClient: PostHog | null = null;
function getPostHogClient(): PostHog {
if (!postHogClient) {
postHogClient = new PostHog(process.env.POSTHOG_API_KEY ?? '', {
host: 'https://us.i.posthog.com',
});
}
return postHogClient;
}

export const createBackendMirrorMiddleware =
<T>(createCommand: (req: Request, data: T) => Promise<string[]>) =>
async (req: Request, res: Response, next: NextFunction) => {
Expand All @@ -12,9 +22,7 @@ export const createBackendMirrorMiddleware =
res.once('finish', () => {
void (async () => {
try {
const postHogClient = new PostHog(process.env.POSTHOG_API_KEY ?? '', {
host: 'https://us.i.posthog.com',
});
const client = getPostHogClient();

console.log('Response finished, checking for mirror work...');
const ok = res.statusCode >= 200 && res.statusCode < 305;
Expand All @@ -23,7 +31,7 @@ export const createBackendMirrorMiddleware =
console.log('Response status:', res.statusCode, 'ok?', ok);

const distinctId = (req as any).user?.id ?? req.ip ?? 'anonymous';
let mirrorOn = await postHogClient.isFeatureEnabled('backend-mirror', distinctId);
let mirrorOn = await client.isFeatureEnabled('backend-mirror', distinctId);
mirrorOn ??= false;

if (!ok || data == null || !mirrorOn) return;
Expand All @@ -32,8 +40,6 @@ export const createBackendMirrorMiddleware =

const queue = MirrorCommandQueue.instance();
queue.enqueue(await createCommand(req, data));

await postHogClient.shutdown();
} catch (e) {
console.error('Error in mirror middleware:', e);
}
Expand Down
68 changes: 68 additions & 0 deletions tests/unit/middleware/legacy/mirror.posthog.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const mockPostHogInstance = {
isFeatureEnabled: jest.fn().mockResolvedValue(true),
shutdown: jest.fn().mockResolvedValue(undefined),
};

const PostHogConstructor = jest.fn(() => mockPostHogInstance);

jest.mock('posthog-node', () => ({
PostHog: PostHogConstructor,
}));

jest.mock('../../../../apps/backend/middleware/legacy/commandqueue.mirror', () => ({
MirrorCommandQueue: {
instance: jest.fn(() => ({
enqueue: jest.fn(),
})),
},
}));

import { createBackendMirrorMiddleware } from '../../../../apps/backend/middleware/legacy/mirror.middleware';
import { Request, Response } from 'express';
import { EventEmitter } from 'events';

function createMockReqRes() {
const req = { user: { id: 'user-1' }, ip: '127.0.0.1' } as unknown as Request;

const res = new EventEmitter() as Response & EventEmitter;
res.statusCode = 200;
(res as any).locals = {};
res.getHeader = jest.fn().mockReturnValue('application/json');
const origSend = jest.fn().mockReturnThis();
res.send = origSend;

return { req, res };
}

describe('PostHog client instantiation', () => {
beforeEach(() => {
PostHogConstructor.mockClear();
mockPostHogInstance.isFeatureEnabled.mockClear();
mockPostHogInstance.shutdown.mockClear();
});

it('creates PostHog at most once across multiple requests', async () => {
const createCommand = jest.fn().mockResolvedValue(['SQL1']);
const middleware = createBackendMirrorMiddleware(createCommand);

const { req: req1, res: res1 } = createMockReqRes();
const { req: req2, res: res2 } = createMockReqRes();
const next = jest.fn();

await middleware(req1, res1, next);
await middleware(req2, res2, next);

// Send responses to populate mirrorData
res1.send(JSON.stringify({ ok: true }));
res2.send(JSON.stringify({ ok: true }));

// Trigger finish events
res1.emit('finish');
res2.emit('finish');

// Allow async callbacks to settle
await new Promise((r) => setTimeout(r, 50));

expect(PostHogConstructor).toHaveBeenCalledTimes(1);
});
});
Loading