Skip to content

Commit 974bcc4

Browse files
authored
Speed up the Run log queries (#1126)
* Added traceId index to TaskEvent * Get less data and get the trace from the run * Use the read replica in the EventRepository * Use the regular client to get the run because the redirect from test can be very fast
1 parent 60cbb87 commit 974bcc4

File tree

6 files changed

+76
-34
lines changed

6 files changed

+76
-34
lines changed

apps/webapp/app/db.server.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ export { Prisma };
7070

7171
export const prisma = singleton("prisma", getClient);
7272

73-
export const $replica: Omit<PrismaClient, "$transaction"> = singleton(
73+
export type PrismaReplicaClient = Omit<PrismaClient, "$transaction">;
74+
75+
export const $replica: PrismaReplicaClient = singleton(
7476
"replica",
7577
() => getReplicaClient() ?? prisma
7678
);

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
import { prettyPrintPacket } from "@trigger.dev/core/v3";
22
import { PrismaClient, prisma } from "~/db.server";
33
import { eventRepository } from "~/v3/eventRepository.server";
4+
import { BasePresenter } from "./basePresenter.server";
45

56
type Result = Awaited<ReturnType<SpanPresenter["call"]>>;
67
export type Span = NonNullable<Result>["event"];
78

8-
export class SpanPresenter {
9-
#prismaClient: PrismaClient;
10-
11-
constructor(prismaClient: PrismaClient = prisma) {
12-
this.#prismaClient = prismaClient;
13-
}
14-
9+
export class SpanPresenter extends BasePresenter {
1510
public async call({
1611
userId,
1712
projectSlug,
1813
organizationSlug,
1914
spanId,
15+
runFriendlyId,
2016
}: {
2117
userId: string;
2218
projectSlug: string;
2319
organizationSlug: string;
2420
spanId: string;
21+
runFriendlyId: string;
2522
}) {
26-
const project = await this.#prismaClient.project.findUnique({
23+
const project = await this._replica.project.findUnique({
2724
where: {
2825
slug: projectSlug,
2926
},
@@ -33,7 +30,20 @@ export class SpanPresenter {
3330
throw new Error("Project not found");
3431
}
3532

36-
const span = await eventRepository.getSpan(spanId);
33+
const run = await this._prisma.taskRun.findFirst({
34+
select: {
35+
traceId: true,
36+
},
37+
where: {
38+
friendlyId: runFriendlyId,
39+
},
40+
});
41+
42+
if (!run) {
43+
return;
44+
}
45+
46+
const span = await eventRepository.getSpan(spanId, run.traceId);
3747

3848
if (!span) {
3949
return;

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.v3.$projectParam.runs.$runParam.spans.$spanParam/route.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import {
44
QueueListIcon,
55
StopCircleIcon,
66
} from "@heroicons/react/20/solid";
7-
import { useFetcher, useParams } from "@remix-run/react";
7+
import { useParams } from "@remix-run/react";
88
import { LoaderFunctionArgs } from "@remix-run/server-runtime";
99
import { formatDurationNanoseconds, nanosecondsToMilliseconds } from "@trigger.dev/core/v3";
1010
import { useEffect } from "react";
11-
import { typedjson, useTypedFetcher, useTypedLoaderData } from "remix-typedjson";
11+
import { typedjson, useTypedFetcher } from "remix-typedjson";
1212
import { ExitIcon } from "~/assets/icons/ExitIcon";
1313
import { CodeBlock } from "~/components/code/CodeBlock";
1414
import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel";
@@ -46,6 +46,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
4646
organizationSlug,
4747
projectSlug: projectParam,
4848
spanId: spanParam,
49+
runFriendlyId: runParam,
4950
});
5051

5152
if (!span) {

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

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { Prisma, TaskEvent, TaskEventStatus, type TaskEventKind } from "@trigger
2222
import Redis, { RedisOptions } from "ioredis";
2323
import { createHash } from "node:crypto";
2424
import { EventEmitter } from "node:stream";
25-
import { PrismaClient, prisma } from "~/db.server";
25+
import { $replica, PrismaClient, PrismaReplicaClient, prisma } from "~/db.server";
2626
import { env } from "~/env.server";
2727
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
2828
import { logger } from "~/services/logger.server";
@@ -101,9 +101,26 @@ export type QueryOptions = Prisma.TaskEventWhereInput;
101101

102102
export type TaskEventRecord = TaskEvent;
103103

104-
export type QueriedEvent = TaskEvent;
104+
export type QueriedEvent = Prisma.TaskEventGetPayload<{
105+
select: {
106+
id: true;
107+
spanId: true;
108+
parentId: true;
109+
runId: true;
110+
idempotencyKey: true;
111+
message: true;
112+
style: true;
113+
startTime: true;
114+
duration: true;
115+
isError: true;
116+
isPartial: true;
117+
isCancelled: true;
118+
level: true;
119+
events: true;
120+
};
121+
}>;
105122

106-
export type PreparedEvent = Omit<TaskEventRecord, "events" | "style" | "duration"> & {
123+
export type PreparedEvent = Omit<QueriedEvent, "events" | "style" | "duration"> & {
107124
duration: number;
108125
events: SpanEvents;
109126
style: TaskEventStyle;
@@ -160,7 +177,11 @@ export class EventRepository {
160177
return this._subscriberCount;
161178
}
162179

163-
constructor(private db: PrismaClient = prisma, private readonly _config: EventRepoConfig) {
180+
constructor(
181+
private db: PrismaClient = prisma,
182+
private readReplica: PrismaReplicaClient = $replica,
183+
private readonly _config: EventRepoConfig
184+
) {
164185
this._flushScheduler = new DynamicFlushScheduler({
165186
batchSize: _config.batchSize,
166187
flushInterval: _config.batchInterval,
@@ -349,7 +370,23 @@ export class EventRepository {
349370
}
350371

351372
public async getTraceSummary(traceId: string): Promise<TraceSummary | undefined> {
352-
const events = await this.db.taskEvent.findMany({
373+
const events = await this.readReplica.taskEvent.findMany({
374+
select: {
375+
id: true,
376+
spanId: true,
377+
parentId: true,
378+
runId: true,
379+
idempotencyKey: true,
380+
message: true,
381+
style: true,
382+
startTime: true,
383+
duration: true,
384+
isError: true,
385+
isPartial: true,
386+
isCancelled: true,
387+
level: true,
388+
events: true,
389+
},
353390
where: {
354391
traceId,
355392
},
@@ -407,29 +444,16 @@ export class EventRepository {
407444

408445
// A Span can be cancelled if it is partial and has a parent that is cancelled
409446
// And a span's duration, if it is partial and has a cancelled parent, is the time between the start of the span and the time of the cancellation event of the parent
410-
public async getSpan(spanId: string) {
411-
const traceSearch = await this.db.taskEvent.findFirst({
412-
where: {
413-
spanId,
414-
},
415-
select: {
416-
traceId: true,
417-
},
418-
});
419-
420-
if (!traceSearch) {
421-
return;
422-
}
423-
424-
const traceSummary = await this.getTraceSummary(traceSearch.traceId);
447+
public async getSpan(spanId: string, traceId: string) {
448+
const traceSummary = await this.getTraceSummary(traceId);
425449

426450
const span = traceSummary?.spans.find((span) => span.id === spanId);
427451

428452
if (!span) {
429453
return;
430454
}
431455

432-
const fullEvent = await this.db.taskEvent.findUnique({
456+
const fullEvent = await this.readReplica.taskEvent.findUnique({
433457
where: {
434458
id: span.recordId,
435459
},
@@ -814,7 +838,7 @@ export class EventRepository {
814838
export const eventRepository = singleton("eventRepo", initializeEventRepo);
815839

816840
function initializeEventRepo() {
817-
const repo = new EventRepository(prisma, {
841+
const repo = new EventRepository(prisma, $replica, {
818842
batchSize: env.EVENTS_BATCH_SIZE,
819843
batchInterval: env.EVENTS_BATCH_INTERVAL,
820844
retentionInDays: env.EVENTS_DEFAULT_LOG_RETENTION,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- CreateIndex
2+
CREATE INDEX "TaskEvent_traceId_idx" ON "TaskEvent"("traceId");

packages/database/prisma/schema.prisma

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,9 @@ model TaskEvent {
18981898
payloadType String?
18991899
19001900
createdAt DateTime @default(now())
1901+
1902+
/// Used on the run page
1903+
@@index([traceId])
19011904
}
19021905

19031906
enum TaskEventLevel {

0 commit comments

Comments
 (0)