Skip to content

Commit ba71f95

Browse files
v3: Runs List Management SDK and SDK improvements (#1133)
* Improved the existing runs API * WIP next runs API * Improve the returned ApiPromise to add ability to return response * More WIP * WI{ * Added offset/limit pagination stuff like the cursor one, and converted all API methods to use ApiPromise * More run API stuff - Adding schedule output from the retrieveRun endpoint - Ability to filter by schedule and isTest * Remove env from retrieve run in openAPI * prefer duplication over merge * WIP docs * Use spread to DRY up some run API schemas * Finish the overview docs * Adding changeset * Fixed typecheck errors * Typo fix * Re-export zodfetch from core so the v3 CLI can use it * Fixed type errors --------- Co-authored-by: Matt Aitken <[email protected]>
1 parent bc7bbd4 commit ba71f95

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+2782
-786
lines changed

.changeset/stupid-adults-sniff.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@trigger.dev/sdk": patch
3+
"@trigger.dev/core": patch
4+
---
5+
6+
Management SDK overhaul and adding the runs.list API

apps/webapp/app/env.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ const EnvironmentSchema = z.object({
170170
MAX_SEQUENTIAL_INDEX_FAILURE_COUNT: z.coerce.number().default(96),
171171

172172
LOOPS_API_KEY: z.string().optional(),
173+
MARQS_DISABLE_REBALANCING: z.coerce.boolean().default(false),
173174
});
174175

175176
export type Environment = z.infer<typeof EnvironmentSchema>;

apps/webapp/app/models/runtimeEnvironment.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ type DisplayableInputEnvironment = Prisma.RuntimeEnvironmentGetPayload<{
124124
select: {
125125
id: true;
126126
type: true;
127+
slug: true;
127128
orgMember: {
128129
select: {
129130
user: {
@@ -155,6 +156,7 @@ export function displayableEnvironment(
155156
return {
156157
id: environment.id,
157158
type: environment.type,
159+
slug: environment.slug,
158160
userName,
159161
};
160162
}

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

Lines changed: 136 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1-
import { AttemptStatus, RetrieveRunResponse, RunStatus, logger } from "@trigger.dev/core/v3";
2-
import { TaskRunAttemptStatus, TaskRunStatus } from "@trigger.dev/database";
1+
import {
2+
AttemptStatus,
3+
RetrieveRunResponse,
4+
RunStatus,
5+
SerializedError,
6+
TaskRunError,
7+
conditionallyImportPacket,
8+
createJsonErrorObject,
9+
logger,
10+
parsePacket,
11+
} from "@trigger.dev/core/v3";
12+
import { Prisma, TaskRunAttemptStatus, TaskRunStatus } from "@trigger.dev/database";
313
import assertNever from "assert-never";
414
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
515
import { BasePresenter } from "./basePresenter.server";
@@ -23,6 +33,7 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
2333
},
2434
},
2535
lockedToVersion: true,
36+
schedule: true,
2637
},
2738
});
2839

@@ -32,14 +43,68 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
3243
return undefined;
3344
}
3445

46+
let $payload: any;
47+
let $output: any;
48+
49+
if (showSecretDetails) {
50+
const payloadPacket = await conditionallyImportPacket({
51+
data: taskRun.payload,
52+
dataType: taskRun.payloadType,
53+
});
54+
55+
$payload =
56+
payloadPacket.dataType === "application/json"
57+
? await parsePacket(payloadPacket)
58+
: payloadPacket.data;
59+
60+
if (taskRun.status === "COMPLETED_SUCCESSFULLY") {
61+
const completedAttempt = taskRun.attempts.find(
62+
(a) => a.status === "COMPLETED" && typeof a.output !== null
63+
);
64+
65+
if (completedAttempt && completedAttempt.output) {
66+
const outputPacket = await conditionallyImportPacket({
67+
data: completedAttempt.output,
68+
dataType: completedAttempt.outputType,
69+
});
70+
71+
$output = await parsePacket(outputPacket);
72+
}
73+
}
74+
}
75+
76+
const apiStatus = ApiRetrieveRunPresenter.apiStatusFromRunStatus(taskRun.status);
77+
3578
return {
3679
id: taskRun.friendlyId,
37-
status: ApiRetrieveRunPresenter.apiStatusFromRunStatus(taskRun.status),
80+
status: apiStatus,
3881
taskIdentifier: taskRun.taskIdentifier,
3982
idempotencyKey: taskRun.idempotencyKey ?? undefined,
4083
version: taskRun.lockedToVersion ? taskRun.lockedToVersion.version : undefined,
4184
createdAt: taskRun.createdAt ?? undefined,
4285
updatedAt: taskRun.updatedAt ?? undefined,
86+
startedAt: taskRun.lockedAt ?? undefined,
87+
finishedAt: ApiRetrieveRunPresenter.isStatusFinished(apiStatus)
88+
? taskRun.updatedAt
89+
: undefined,
90+
payload: $payload,
91+
output: $output,
92+
isTest: taskRun.isTest,
93+
schedule: taskRun.schedule
94+
? {
95+
id: taskRun.schedule.friendlyId,
96+
externalId: taskRun.schedule.externalId ?? undefined,
97+
deduplicationKey: taskRun.schedule.userProvidedDeduplicationKey
98+
? taskRun.schedule.deduplicationKey
99+
: undefined,
100+
generator: {
101+
type: "CRON",
102+
expression: taskRun.schedule.generatorExpression,
103+
description: taskRun.schedule.generatorDescription,
104+
},
105+
}
106+
: undefined,
107+
...ApiRetrieveRunPresenter.apiBooleanHelpersFromRunStatus(apiStatus),
43108
attempts: !showSecretDetails
44109
? []
45110
: taskRun.attempts.map((a) => ({
@@ -49,34 +114,68 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
49114
updatedAt: a.updatedAt ?? undefined,
50115
startedAt: a.startedAt ?? undefined,
51116
completedAt: a.completedAt ?? undefined,
117+
error: ApiRetrieveRunPresenter.apiErrorFromError(a.error),
52118
})),
53119
};
54120
});
55121
}
56122

123+
static apiErrorFromError(error: Prisma.JsonValue): SerializedError | undefined {
124+
if (!error) {
125+
return;
126+
}
127+
128+
const errorData = TaskRunError.safeParse(error);
129+
130+
if (errorData.success) {
131+
return createJsonErrorObject(errorData.data);
132+
}
133+
}
134+
135+
static isStatusFinished(status: RunStatus) {
136+
return (
137+
status === "COMPLETED" ||
138+
status === "FAILED" ||
139+
status === "CANCELED" ||
140+
status === "INTERRUPTED" ||
141+
status === "CRASHED" ||
142+
status === "SYSTEM_FAILURE"
143+
);
144+
}
145+
57146
static apiStatusFromRunStatus(status: TaskRunStatus): RunStatus {
58147
switch (status) {
59-
case "WAITING_FOR_DEPLOY":
148+
case "WAITING_FOR_DEPLOY": {
149+
return "WAITING_FOR_DEPLOY";
150+
}
60151
case "PENDING": {
61-
return "PENDING";
152+
return "QUEUED";
153+
}
154+
case "PAUSED":
155+
case "WAITING_TO_RESUME": {
156+
return "FROZEN";
157+
}
158+
case "RETRYING_AFTER_FAILURE": {
159+
return "REATTEMPTING";
62160
}
63-
case "RETRYING_AFTER_FAILURE":
64161
case "EXECUTING": {
65162
return "EXECUTING";
66163
}
67-
case "WAITING_TO_RESUME":
68-
case "PAUSED": {
69-
return "PAUSED";
70-
}
71164
case "CANCELED": {
72165
return "CANCELED";
73166
}
74167
case "COMPLETED_SUCCESSFULLY": {
75168
return "COMPLETED";
76169
}
77-
case "SYSTEM_FAILURE":
78-
case "INTERRUPTED":
79-
case "CRASHED":
170+
case "SYSTEM_FAILURE": {
171+
return "SYSTEM_FAILURE";
172+
}
173+
case "INTERRUPTED": {
174+
return "INTERRUPTED";
175+
}
176+
case "CRASHED": {
177+
return "CRASHED";
178+
}
80179
case "COMPLETED_WITH_ERRORS": {
81180
return "FAILED";
82181
}
@@ -86,6 +185,30 @@ export class ApiRetrieveRunPresenter extends BasePresenter {
86185
}
87186
}
88187

188+
static apiBooleanHelpersFromRunStatus(status: RunStatus) {
189+
const isQueued = status === "QUEUED" || status === "WAITING_FOR_DEPLOY";
190+
const isExecuting = status === "EXECUTING" || status === "REATTEMPTING" || status === "FROZEN";
191+
const isCompleted =
192+
status === "COMPLETED" ||
193+
status === "CANCELED" ||
194+
status === "FAILED" ||
195+
status === "CRASHED" ||
196+
status === "INTERRUPTED" ||
197+
status === "SYSTEM_FAILURE";
198+
const isFailed = isCompleted && status !== "COMPLETED";
199+
const isSuccess = isCompleted && status === "COMPLETED";
200+
const isCancelled = status === "CANCELED";
201+
202+
return {
203+
isQueued,
204+
isExecuting,
205+
isCompleted,
206+
isFailed,
207+
isSuccess,
208+
isCancelled,
209+
};
210+
}
211+
89212
static apiStatusFromAttemptStatus(status: TaskRunAttemptStatus): AttemptStatus {
90213
switch (status) {
91214
case "PENDING": {

0 commit comments

Comments
 (0)