Skip to content

Commit e9db1e9

Browse files
Move Postgres event repository fallback out of ClickHouse factory
The factory should not import eventRepository.server.ts — doing so pulls the tracePubSub singleton into any module graph that imports the factory, which eagerly connects to Redis at module load time (see singleton.ts). The fallback now lives in index.server.ts via getEventRepositoryForStore, which is called from RunPresenter, SpanPresenter, and recordRunEvent. This restores runsReplicationBenchmark.test.ts's module isolation while still handling non-ClickHouse ("taskEvent"/"postgres") stores. Co-Authored-By: Matt Aitken <matt@mattaitken.com>
1 parent b1694a3 commit e9db1e9

File tree

4 files changed

+29
-18
lines changed

4 files changed

+29
-18
lines changed

apps/webapp/app/presenters/v3/RunPresenter.server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { SpanSummary } from "~/v3/eventRepository/eventRepository.types";
77
import { getTaskEventStoreTableForRun } from "~/v3/taskEventStore.server";
88
import { isFinalRunStatus } from "~/v3/taskStatus";
99
import { env } from "~/env.server";
10-
import { clickhouseFactory } from "~/services/clickhouse/clickhouseFactory.server";
10+
import { getEventRepositoryForStore } from "~/v3/eventRepository/index.server";
1111

1212
type Result = Awaited<ReturnType<RunPresenter["call"]>>;
1313
export type Run = Result["run"];
@@ -145,7 +145,7 @@ export class RunPresenter {
145145
};
146146
}
147147

148-
const { repository } = await clickhouseFactory.getEventRepositoryForOrganization(
148+
const repository = await getEventRepositoryForStore(
149149
run.taskEventStore,
150150
run.runtimeEnvironment.organizationId
151151
);

apps/webapp/app/presenters/v3/SpanPresenter.server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
extractAIToolCallData,
3030
extractAIEmbedData,
3131
} from "~/components/runs/v3/ai";
32-
import { clickhouseFactory } from "~/services/clickhouse/clickhouseFactory.server";
32+
import { getEventRepositoryForStore } from "~/v3/eventRepository/index.server";
3333

3434
export type PromptSpanData = {
3535
slug: string;
@@ -130,7 +130,7 @@ export class SpanPresenter extends BasePresenter {
130130

131131
const { traceId } = parentRun;
132132

133-
const { repository } = await clickhouseFactory.getEventRepositoryForOrganization(
133+
const repository = await getEventRepositoryForStore(
134134
parentRun.taskEventStore,
135135
project.organizationId
136136
);

apps/webapp/app/services/clickhouse/clickhouseFactory.server.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { singleton } from "~/utils/singleton";
66
import { organizationDataStoresRegistry } from "~/services/dataStores/organizationDataStoresRegistryInstance.server";
77
import type { OrganizationDataStoresRegistry } from "~/services/dataStores/organizationDataStoresRegistry.server";
88
import { type IEventRepository } from "~/v3/eventRepository/eventRepository.types";
9-
import { eventRepository as postgresEventRepository } from "~/v3/eventRepository/eventRepository.server";
109

1110
// ---------------------------------------------------------------------------
1211
// Default clients (singleton per process)
@@ -255,14 +254,6 @@ export class ClickhouseFactory {
255254
store: string,
256255
organizationId: string
257256
): { key: string; repository: IEventRepository } {
258-
// Non-ClickHouse stores (e.g. the "taskEvent" DB default for Postgres-backed
259-
// runs, or "postgres") fall back to the Prisma event repository. This lets
260-
// callers pass `run.taskEventStore` directly without needing to guard
261-
// against legacy/Postgres values.
262-
if (store !== "clickhouse" && store !== "clickhouse_v2") {
263-
return { key: `postgres:${store}`, repository: postgresEventRepository };
264-
}
265-
266257
const dataStore = this._registry.get(organizationId, "CLICKHOUSE");
267258

268259
if (!dataStore) {

apps/webapp/app/v3/eventRepository/index.server.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ export function resolveEventRepositoryForStore(
3232
return eventRepository;
3333
}
3434

35+
/**
36+
* Async variant of {@link resolveEventRepositoryForStore}. Awaits the factory's
37+
* registry readiness before returning the ClickHouse event repository; for
38+
* non-ClickHouse stores (e.g. the "taskEvent" DB default for Postgres-backed
39+
* runs) it returns the Prisma event repository without ever touching the
40+
* factory — so the factory never needs to know about Postgres.
41+
*/
42+
export async function getEventRepositoryForStore(
43+
store: string,
44+
organizationId: string
45+
): Promise<IEventRepository> {
46+
if (store !== EVENT_STORE_TYPES.CLICKHOUSE && store !== EVENT_STORE_TYPES.CLICKHOUSE_V2) {
47+
return eventRepository;
48+
}
49+
const { repository } = await clickhouseFactory.getEventRepositoryForOrganization(
50+
store,
51+
organizationId
52+
);
53+
return repository;
54+
}
55+
3556
export async function getConfiguredEventRepository(
3657
organizationId: string
3758
): Promise<{ repository: IEventRepository; store: EventStoreType }> {
@@ -219,11 +240,10 @@ async function recordRunEvent(
219240
};
220241
}
221242

222-
const { repository: $eventRepository } =
223-
await clickhouseFactory.getEventRepositoryForOrganization(
224-
foundRun.taskEventStore,
225-
foundRun.runtimeEnvironment.organizationId
226-
);
243+
const $eventRepository = await getEventRepositoryForStore(
244+
foundRun.taskEventStore,
245+
foundRun.runtimeEnvironment.organizationId
246+
);
227247

228248
const { attributes, startTime, ...optionsRest } = options;
229249

0 commit comments

Comments
 (0)