From 73c4b4e6dd3b377fa0f1b48845e098419befd24c Mon Sep 17 00:00:00 2001 From: myftija Date: Thu, 30 Oct 2025 15:36:40 +0100 Subject: [PATCH 1/6] Add an API endpoint to query remote build provider status --- .../api.v1.remote-build-provider-status.ts | 94 +++++++++++++++++++ packages/core/src/v3/schemas/api.ts | 9 ++ 2 files changed, 103 insertions(+) create mode 100644 apps/webapp/app/routes/api.v1.remote-build-provider-status.ts diff --git a/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts b/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts new file mode 100644 index 0000000000..27eec25dff --- /dev/null +++ b/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts @@ -0,0 +1,94 @@ +import { json } from "@remix-run/node"; +import { err, fromPromise, fromSafePromise, ok } from "neverthrow"; +import z from "zod"; +import { logger } from "~/services/logger.server"; +import { type RemoteBuildProviderStatusResponseBody } from "../../../../packages/core/src/v3/schemas/api"; + +const DEPOT_STATUS_URL = "https://status.depot.dev/proxy/status.depot.dev"; +const FETCH_TIMEOUT_MS = 2000; + +export async function loader() { + return await fetchDepotStatus().match( + ({ summary: { ongoing_incidents } }) => { + if (ongoing_incidents.length > 0) { + return json( + { + status: "degraded", + message: + "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", + } satisfies RemoteBuildProviderStatusResponseBody, + { status: 200 } + ); + } + + return json( + { + status: "operational", + message: "Depot is operational", + } satisfies RemoteBuildProviderStatusResponseBody, + { status: 200 } + ); + }, + () => { + return json( + { + status: "unknown", + message: "Failed to fetch remote build provider status", + } satisfies RemoteBuildProviderStatusResponseBody, + { status: 200 } + ); + } + ); +} + +function fetchDepotStatus() { + return fromPromise( + fetch(DEPOT_STATUS_URL, { + signal: AbortSignal.timeout(FETCH_TIMEOUT_MS), + }), + (error) => { + if ( + error instanceof Error && + (error.name === "TimeoutError" || error.name === "AbortError") + ) { + return { + type: "timeout" as const, + }; + } + + return { + type: "other" as const, + cause: error, + }; + } + ) + .andThen((response) => { + if (!response.ok) { + return err({ + type: "other" as const, + cause: new Error(`Failed to fetch Depot status: ${response.status}`), + }); + } + + return fromSafePromise(response.json()); + }) + .andThen((json) => { + const parsed = DepotStatusResponseSchema.safeParse(json); + + if (!parsed.success) { + logger.warn("Invalid Depot status response", { error: parsed.error }); + return err({ + type: "validation_failed" as const, + }); + } + + return ok(parsed.data); + }); +} + +// partial schema +const DepotStatusResponseSchema = z.object({ + summary: z.object({ + ongoing_incidents: z.array(z.any()), + }), +}); diff --git a/packages/core/src/v3/schemas/api.ts b/packages/core/src/v3/schemas/api.ts index c86f302a66..b018b2a4a8 100644 --- a/packages/core/src/v3/schemas/api.ts +++ b/packages/core/src/v3/schemas/api.ts @@ -439,6 +439,15 @@ export const InitializeDeploymentRequestBody = z.object({ export type InitializeDeploymentRequestBody = z.infer; +export const RemoteBuildProviderStatusResponseBody = z.object({ + status: z.enum(["operational", "degraded", "unknown"]), + message: z.string(), +}); + +export type RemoteBuildProviderStatusResponseBody = z.infer< + typeof RemoteBuildProviderStatusResponseBody +>; + export const GenerateRegistryCredentialsResponseBody = z.object({ username: z.string(), password: z.string(), From 7cc05bc5f11dd8d3b40131701847f93cd85c8ba5 Mon Sep 17 00:00:00 2001 From: myftija Date: Thu, 30 Oct 2025 15:40:19 +0100 Subject: [PATCH 2/6] Show local build hint for failed deployments when Depot is down --- packages/cli-v3/src/apiClient.ts | 18 +++++++++++++++++- packages/cli-v3/src/commands/deploy.ts | 19 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/cli-v3/src/apiClient.ts b/packages/cli-v3/src/apiClient.ts index 6f65bce114..4a2f6232c0 100644 --- a/packages/cli-v3/src/apiClient.ts +++ b/packages/cli-v3/src/apiClient.ts @@ -22,7 +22,6 @@ import { PromoteDeploymentResponseBody, StartDeploymentIndexingRequestBody, StartDeploymentIndexingResponseBody, - TaskRunExecution, TriggerTaskRequestBody, TriggerTaskResponse, UpsertBranchRequestBody, @@ -38,6 +37,7 @@ import { GetJWTResponse, ApiBranchListResponseBody, GenerateRegistryCredentialsResponseBody, + RemoteBuildProviderStatusResponseBody, } from "@trigger.dev/core/v3"; import { WorkloadDebugLogRequestBody, @@ -52,6 +52,7 @@ import { ApiResult, wrapZodFetch, zodfetchSSE } from "@trigger.dev/core/v3/zodfe import { EventSource } from "eventsource"; import { z } from "zod"; import { logger } from "./utilities/logger.js"; +import { VERSION } from "./version.js"; export class CliApiClient { private engineURL: string; @@ -328,6 +329,21 @@ export class CliApiClient { ); } + async getRemoteBuildProviderStatus() { + return wrapZodFetch( + RemoteBuildProviderStatusResponseBody, + `${this.apiURL}/api/v1/remote-build-provider-status`, + { + method: "GET", + headers: { + ...this.getHeaders(), + // probably a good idea to add this to the other requests too + "x-trigger-cli-version": VERSION, + }, + } + ); + } + async generateRegistryCredentials(deploymentId: string) { if (!this.accessToken) { throw new Error("generateRegistryCredentials: No access token"); diff --git a/packages/cli-v3/src/commands/deploy.ts b/packages/cli-v3/src/commands/deploy.ts index 4c7bbd92bf..1329518e0e 100644 --- a/packages/cli-v3/src/commands/deploy.ts +++ b/packages/cli-v3/src/commands/deploy.ts @@ -28,7 +28,13 @@ import { printWarnings, saveLogs, } from "../deploy/logs.js"; -import { chalkError, cliLink, isLinksSupported, prettyError } from "../utilities/cliOutput.js"; +import { + chalkError, + cliLink, + isLinksSupported, + prettyError, + prettyWarning, +} from "../utilities/cliOutput.js"; import { loadDotEnvVars } from "../utilities/dotEnv.js"; import { isDirectory } from "../utilities/fileSystem.js"; import { setGithubActionsOutputAndEnvVars } from "../utilities/githubActions.js"; @@ -458,6 +464,17 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) { const warnings = checkLogsForWarnings(buildResult.logs); + const canShowLocalBuildHint = !isLocalBuild && !process.env.TRIGGER_LOCAL_BUILD_HINT_DISABLED; + const buildFailed = !warnings.ok || !buildResult.ok; + + if (buildFailed && canShowLocalBuildHint) { + const providerStatus = await projectClient.client.getRemoteBuildProviderStatus(); + + if (providerStatus.success && providerStatus.data.status === "degraded") { + prettyWarning(providerStatus.data.message + "\n"); + } + } + if (!warnings.ok) { await failDeploy( projectClient.client, From ba6c809c0548ab92eb64fa67d026921e9c38445d Mon Sep 17 00:00:00 2001 From: myftija Date: Thu, 30 Oct 2025 15:56:50 +0100 Subject: [PATCH 3/6] Show the local build flag in the help output --- packages/cli-v3/src/commands/deploy.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/cli-v3/src/commands/deploy.ts b/packages/cli-v3/src/commands/deploy.ts index 1329518e0e..36f35d442e 100644 --- a/packages/cli-v3/src/commands/deploy.ts +++ b/packages/cli-v3/src/commands/deploy.ts @@ -134,9 +134,7 @@ export function configureDeployCommand(program: Command) { ).hideHelp() ) // Local build options - .addOption( - new CommandOption("--force-local-build", "Force a local build of the image").hideHelp() - ) + .addOption(new CommandOption("--force-local-build", "Force a local build of the image")) .addOption(new CommandOption("--push", "Push the image after local builds").hideHelp()) .addOption( new CommandOption("--no-push", "Do not push the image after local builds").hideHelp() From 28ab123ca70ab7dcd4330887be801d3823a275bc Mon Sep 17 00:00:00 2001 From: myftija Date: Thu, 30 Oct 2025 15:59:26 +0100 Subject: [PATCH 4/6] Add changeset --- .changeset/nice-pillows-hide.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/nice-pillows-hide.md diff --git a/.changeset/nice-pillows-hide.md b/.changeset/nice-pillows-hide.md new file mode 100644 index 0000000000..c8a00be105 --- /dev/null +++ b/.changeset/nice-pillows-hide.md @@ -0,0 +1,6 @@ +--- +"trigger.dev": patch +"@trigger.dev/core": patch +--- + +Added a hint about the `--force-local-build` flag on failed deployments due to upstream provider outages. From 507bcb94d20df65320b9ac030afca989e1cab61b Mon Sep 17 00:00:00 2001 From: myftija Date: Thu, 30 Oct 2025 17:18:05 +0100 Subject: [PATCH 5/6] Fix import --- apps/webapp/app/routes/api.v1.remote-build-provider-status.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts b/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts index 27eec25dff..c991a90532 100644 --- a/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts +++ b/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts @@ -2,7 +2,7 @@ import { json } from "@remix-run/node"; import { err, fromPromise, fromSafePromise, ok } from "neverthrow"; import z from "zod"; import { logger } from "~/services/logger.server"; -import { type RemoteBuildProviderStatusResponseBody } from "../../../../packages/core/src/v3/schemas/api"; +import { type RemoteBuildProviderStatusResponseBody } from "@trigger.dev/core/v3/schemas"; const DEPOT_STATUS_URL = "https://status.depot.dev/proxy/status.depot.dev"; const FETCH_TIMEOUT_MS = 2000; From d69838e1ab964599412f5ade3a8b6e900f6dfa55 Mon Sep 17 00:00:00 2001 From: myftija Date: Thu, 30 Oct 2025 17:20:46 +0100 Subject: [PATCH 6/6] Fix docs link --- apps/webapp/app/routes/api.v1.remote-build-provider-status.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts b/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts index c991a90532..555194e34d 100644 --- a/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts +++ b/apps/webapp/app/routes/api.v1.remote-build-provider-status.ts @@ -15,7 +15,7 @@ export async function loader() { { status: "degraded", message: - "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", + "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://trigger.dev/docs/deployment/overview#local-builds", } satisfies RemoteBuildProviderStatusResponseBody, { status: 200 } );