Skip to content

Commit 73c4b4e

Browse files
committed
Add an API endpoint to query remote build provider status
1 parent 4264bdf commit 73c4b4e

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { json } from "@remix-run/node";
2+
import { err, fromPromise, fromSafePromise, ok } from "neverthrow";
3+
import z from "zod";
4+
import { logger } from "~/services/logger.server";
5+
import { type RemoteBuildProviderStatusResponseBody } from "../../../../packages/core/src/v3/schemas/api";
6+
7+
const DEPOT_STATUS_URL = "https://status.depot.dev/proxy/status.depot.dev";
8+
const FETCH_TIMEOUT_MS = 2000;
9+
10+
export async function loader() {
11+
return await fetchDepotStatus().match(
12+
({ summary: { ongoing_incidents } }) => {
13+
if (ongoing_incidents.length > 0) {
14+
return json(
15+
{
16+
status: "degraded",
17+
message:
18+
"Our remote build provider is currently facing issues. You can use the `--force-local-build` flag to build and deploy the image locally. Read more about local builds here: https://docs.trigger.dev/deploy/local-builds",
19+
} satisfies RemoteBuildProviderStatusResponseBody,
20+
{ status: 200 }
21+
);
22+
}
23+
24+
return json(
25+
{
26+
status: "operational",
27+
message: "Depot is operational",
28+
} satisfies RemoteBuildProviderStatusResponseBody,
29+
{ status: 200 }
30+
);
31+
},
32+
() => {
33+
return json(
34+
{
35+
status: "unknown",
36+
message: "Failed to fetch remote build provider status",
37+
} satisfies RemoteBuildProviderStatusResponseBody,
38+
{ status: 200 }
39+
);
40+
}
41+
);
42+
}
43+
44+
function fetchDepotStatus() {
45+
return fromPromise(
46+
fetch(DEPOT_STATUS_URL, {
47+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
48+
}),
49+
(error) => {
50+
if (
51+
error instanceof Error &&
52+
(error.name === "TimeoutError" || error.name === "AbortError")
53+
) {
54+
return {
55+
type: "timeout" as const,
56+
};
57+
}
58+
59+
return {
60+
type: "other" as const,
61+
cause: error,
62+
};
63+
}
64+
)
65+
.andThen((response) => {
66+
if (!response.ok) {
67+
return err({
68+
type: "other" as const,
69+
cause: new Error(`Failed to fetch Depot status: ${response.status}`),
70+
});
71+
}
72+
73+
return fromSafePromise(response.json());
74+
})
75+
.andThen((json) => {
76+
const parsed = DepotStatusResponseSchema.safeParse(json);
77+
78+
if (!parsed.success) {
79+
logger.warn("Invalid Depot status response", { error: parsed.error });
80+
return err({
81+
type: "validation_failed" as const,
82+
});
83+
}
84+
85+
return ok(parsed.data);
86+
});
87+
}
88+
89+
// partial schema
90+
const DepotStatusResponseSchema = z.object({
91+
summary: z.object({
92+
ongoing_incidents: z.array(z.any()),
93+
}),
94+
});

packages/core/src/v3/schemas/api.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,15 @@ export const InitializeDeploymentRequestBody = z.object({
439439

440440
export type InitializeDeploymentRequestBody = z.infer<typeof InitializeDeploymentRequestBody>;
441441

442+
export const RemoteBuildProviderStatusResponseBody = z.object({
443+
status: z.enum(["operational", "degraded", "unknown"]),
444+
message: z.string(),
445+
});
446+
447+
export type RemoteBuildProviderStatusResponseBody = z.infer<
448+
typeof RemoteBuildProviderStatusResponseBody
449+
>;
450+
442451
export const GenerateRegistryCredentialsResponseBody = z.object({
443452
username: z.string(),
444453
password: z.string(),

0 commit comments

Comments
 (0)