Files
triggerdotdev--trigger.dev/apps/webapp/app/presenters/RunListPresenter.server.ts
Eric Allam 34ca7667d3 Various perf improvements to prevent event loop lag (#1186)
* WIP

* Handle tasks that have failed but are being auto yielded

* Limit trace view to 25k event records, add a download run logs button

Also added two new indexes to TaskEvent:

```
/// Used on eventRepository.getTraceSummary()
  @@index([traceId, startTime])
  // Used for getting all logs for a run
  @@index([runId])
```

* perf improvements on eventRepository.getSpan()

* v2: Add a 5 minute timeout for run execution requests in dev

* v3: Include presigned urls for downloading large payloads and outputs when using runs.retrieve

* v3: better handle large task payloads and outputs

* Change to 512KB

* v2: paginate trigger schedules endpoint

* v3: add 3MB limit on batch and single payloads

* Update task payload and output limits
2024-06-26 15:22:35 +01:00

197 lines
4.9 KiB
TypeScript

import {
Direction,
FilterableEnvironment,
FilterableStatus,
filterableStatuses,
} from "~/components/runs/RunStatuses";
import { getUsername } from "~/utils/username";
import { BasePresenter } from "./v3/basePresenter.server";
type RunListOptions = {
userId: string;
eventId?: string;
jobSlug?: string;
organizationSlug: string;
projectSlug: string;
direction?: Direction;
filterStatus?: FilterableStatus;
filterEnvironment?: FilterableEnvironment;
cursor?: string;
pageSize?: number;
from?: number;
to?: number;
};
const DEFAULT_PAGE_SIZE = 20;
export type RunList = Awaited<ReturnType<RunListPresenter["call"]>>;
export class RunListPresenter extends BasePresenter {
public async call({
userId,
eventId,
jobSlug,
organizationSlug,
projectSlug,
filterEnvironment,
filterStatus,
direction = "forward",
cursor,
pageSize = DEFAULT_PAGE_SIZE,
from,
to,
}: RunListOptions) {
const filterStatuses = filterStatus ? filterableStatuses[filterStatus] : undefined;
const directionMultiplier = direction === "forward" ? 1 : -1;
// Find the organization that the user is a member of
const organization = await this._replica.organization.findFirstOrThrow({
select: {
id: true,
},
where: {
slug: organizationSlug,
members: { some: { userId } },
},
});
// Find the project scoped to the organization
const project = await this._replica.project.findFirstOrThrow({
select: {
id: true,
},
where: {
slug: projectSlug,
organizationId: organization.id,
},
});
const job = jobSlug
? await this._replica.job.findFirstOrThrow({
where: {
slug: jobSlug,
projectId: project.id,
},
})
: undefined;
const event = eventId
? await this._replica.eventRecord.findUnique({ where: { id: eventId } })
: undefined;
const runs = await this._replica.jobRun.findMany({
select: {
id: true,
number: true,
startedAt: true,
completedAt: true,
createdAt: true,
executionDuration: true,
isTest: true,
status: true,
environment: {
select: {
type: true,
slug: true,
orgMember: {
select: {
user: {
select: {
id: true,
name: true,
displayName: true,
},
},
},
},
},
},
version: {
select: {
version: true,
},
},
job: {
select: {
slug: true,
title: true,
},
},
},
where: {
eventId: event?.id,
jobId: job?.id,
projectId: project.id,
organizationId: organization.id,
status: filterStatuses ? { in: filterStatuses } : undefined,
environment: filterEnvironment ? { type: filterEnvironment } : undefined,
startedAt: {
gte: from ? new Date(from).toISOString() : undefined,
lte: to ? new Date(to).toISOString() : undefined,
},
},
orderBy: [{ id: "desc" }],
//take an extra record to tell if there are more
take: directionMultiplier * (pageSize + 1),
//skip the cursor if there is one
skip: cursor ? 1 : 0,
cursor: cursor
? {
id: cursor,
}
: undefined,
});
const hasMore = runs.length > pageSize;
//get cursors for next and previous pages
let next: string | undefined;
let previous: string | undefined;
switch (direction) {
case "forward":
previous = cursor ? runs.at(0)?.id : undefined;
if (hasMore) {
next = runs[pageSize - 1]?.id;
}
break;
case "backward":
if (hasMore) {
previous = runs[1]?.id;
next = runs[pageSize]?.id;
} else {
next = runs[pageSize - 1]?.id;
}
break;
}
const runsToReturn =
direction === "backward" && hasMore ? runs.slice(1, pageSize + 1) : runs.slice(0, pageSize);
return {
runs: runsToReturn.map((run) => ({
id: run.id,
number: run.number,
startedAt: run.startedAt,
completedAt: run.completedAt,
createdAt: run.createdAt,
executionDuration: run.executionDuration,
isTest: run.isTest,
status: run.status,
version: run.version?.version ?? "unknown",
environment: {
type: run.environment.type,
slug: run.environment.slug,
userId: run.environment.orgMember?.user.id,
userName: getUsername(run.environment.orgMember?.user),
},
job: run.job,
})),
pagination: {
next,
previous,
},
};
}
}