Skip to content

Commit 8f3c622

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 7f473c6 commit 8f3c622

4 files changed

Lines changed: 29 additions & 18 deletions

File tree

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
@@ -31,7 +31,7 @@ import {
3131
extractAIToolCallData,
3232
extractAIEmbedData,
3333
} from "~/components/runs/v3/ai";
34-
import { clickhouseFactory } from "~/services/clickhouse/clickhouseFactory.server";
34+
import { getEventRepositoryForStore } from "~/v3/eventRepository/index.server";
3535

3636
export type PromptSpanData = {
3737
slug: string;
@@ -132,7 +132,7 @@ export class SpanPresenter extends BasePresenter {
132132

133133
const { traceId } = parentRun;
134134

135-
const { repository } = await clickhouseFactory.getEventRepositoryForOrganization(
135+
const repository = await getEventRepositoryForStore(
136136
parentRun.taskEventStore,
137137
project.organizationId
138138
);

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)