From 5889e8c6deb6e134fca34431de822b717b9936a5 Mon Sep 17 00:00:00 2001 From: Harsh Mahajan <127186841+HarshMN2345@users.noreply.github.com> Date: Mon, 27 Oct 2025 18:24:49 +0530 Subject: [PATCH 1/9] feat: add build timeout handling to prevent stuck build UI --- package.json | 2 +- pnpm-lock.yaml | 10 ++-- src/lib/helpers/buildTimeout.ts | 51 +++++++++++++++++++ .../deployment-[deployment]/+page.svelte | 21 +++++--- .../function-[function]/table.svelte | 17 ++++--- .../(components)/deploymentActionMenu.svelte | 7 ++- .../sites/(components)/logs.svelte | 26 +++++++--- .../sites/(components)/logsTimer.svelte | 11 ++-- .../sites/(components)/siteCard.svelte | 15 ++++-- .../deployment-[deployment]/+page.svelte | 15 ++++-- .../site-[site]/deployments/table.svelte | 12 +++-- 11 files changed, 146 insertions(+), 41 deletions(-) create mode 100644 src/lib/helpers/buildTimeout.ts diff --git a/package.json b/package.json index 8d1a0d1ba2..199f031c58 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@fe3277e", + "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2755", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc", "@appwrite.io/pink-legacy": "^1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 463bb83f37..599224abda 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^1.1.24 version: 1.1.24(svelte@5.25.3)(zod@3.24.3) '@appwrite.io/console': - specifier: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@fe3277e - version: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@fe3277e + specifier: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2755 + version: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2755 '@appwrite.io/pink-icons': specifier: 0.25.0 version: 0.25.0 @@ -260,8 +260,8 @@ packages: '@analytics/type-utils@0.6.2': resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==} - '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@fe3277e': - resolution: {tarball: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@fe3277e} + '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2755': + resolution: {tarball: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2755} version: 1.10.0 '@appwrite.io/pink-icons-svelte@2.0.0-RC.1': @@ -3703,7 +3703,7 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@fe3277e': {} + '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@2755': {} '@appwrite.io/pink-icons-svelte@2.0.0-RC.1(svelte@5.25.3)': dependencies: diff --git a/src/lib/helpers/buildTimeout.ts b/src/lib/helpers/buildTimeout.ts new file mode 100644 index 0000000000..b57a020fdc --- /dev/null +++ b/src/lib/helpers/buildTimeout.ts @@ -0,0 +1,51 @@ +import type { Models } from '@appwrite.io/console'; + +/** + * Checks if a build has exceeded the maximum build timeout duration + */ +export function isBuildTimedOut( + createdAt: string, + status: string, + timeoutSeconds: number +): boolean { + if (!['waiting', 'processing', 'building'].includes(status)) { + return false; + } + + if (!timeoutSeconds || timeoutSeconds <= 0) { + return false; + } + + const now = new Date(); + const created = new Date(createdAt); + const elapsedSeconds = Math.floor((now.getTime() - created.getTime()) / 1000); + + return elapsedSeconds > timeoutSeconds; +} + +/** + * Gets the effective status for a build, considering timeout + */ +export function getEffectiveBuildStatus( + originalStatus: string, + createdAt: string, + timeoutSeconds: number +): string { + if (isBuildTimedOut(createdAt, originalStatus, timeoutSeconds)) { + return 'failed'; + } + return originalStatus; +} + +/** + * Helper to get timeout value from console variables + */ +export function getBuildTimeoutSeconds( + consoleVariables: Models.ConsoleVariables | undefined +): number { + if (!consoleVariables?._APP_COMPUTE_BUILD_TIMEOUT) { + return 0; + } + const timeout = parseInt(String(consoleVariables._APP_COMPUTE_BUILD_TIMEOUT), 10); + return isNaN(timeout) ? 0 : timeout; +} diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte index 83247cdb2e..636d296fe4 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte @@ -24,6 +24,8 @@ } from '@appwrite.io/pink-svelte'; import { capitalize } from '$lib/helpers/string'; import { formatTimeDetailed } from '$lib/helpers/timeConversion'; + import { getEffectiveBuildStatus, getBuildTimeoutSeconds } from '$lib/helpers/buildTimeout'; + import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; import { timer } from '$lib/actions/timer'; import { app } from '$lib/stores/app'; import { IconDotsHorizontal, IconRefresh } from '@appwrite.io/pink-icons-svelte'; @@ -36,12 +38,19 @@ import { readOnly } from '$lib/stores/billing'; import RedeployModal from '../(modals)/redeployModal.svelte'; - export let data; + let { data } = $props(); - let showDelete = false; - let showCancel = false; - let showActivate = false; - let showRedeploy = false; + let effectiveStatus = $derived( + getEffectiveBuildStatus( + data.deployment.status, + data.deployment.$createdAt, + getBuildTimeoutSeconds($regionalConsoleVariables) + ) + ); + let showDelete = $state(false); + let showCancel = $state(false); + let showActivate = $state(false); + let showRedeploy = $state(false); onMount(() => { const unsubscribe = sdk.forConsole.client.subscribe( @@ -84,7 +93,7 @@ {#snippet footer()} - {#if data.deployment.status === 'processing' || data.deployment.status === 'building' || data.deployment.status === 'waiting'} + {#if effectiveStatus === 'processing' || effectiveStatus === 'building' || effectiveStatus === 'waiting'} + {@const effectiveStatus = getEffectiveBuildStatus( + deployment.status, + deployment.$createdAt, + getBuildTimeoutSeconds($regionalConsoleVariables) + )} {#if !inCard}
@@ -72,7 +77,7 @@
Source is empty
{/if} - {#if deployment?.status === 'ready' && deployment?.$id !== activeDeployment} + {#if effectiveStatus === 'ready' && deployment?.$id !== activeDeployment} { @@ -84,7 +89,7 @@ Activate {/if} - {#if deployment?.status === 'ready' || deployment?.status === 'failed' || deployment?.status === 'building'} + {#if effectiveStatus === 'ready' || effectiveStatus === 'failed' || effectiveStatus === 'building'} @@ -114,11 +119,6 @@ {/if} - {@const effectiveStatus = getEffectiveBuildStatus( - deployment.status, - deployment.$createdAt, - getBuildTimeoutSeconds($regionalConsoleVariables) - )} {#if effectiveStatus === 'processing' || effectiveStatus === 'building' || effectiveStatus === 'waiting'} diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte index 075c746c7a..3387336af4 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte @@ -62,7 +62,7 @@ {#snippet footer()} - {#if deployment?.status === 'ready' && data.proxyRuleList?.total} + {#if effectiveStatus === 'ready' && data.proxyRuleList?.total}