From aa780492fd6be1409628def30eac385855600f98 Mon Sep 17 00:00:00 2001 From: mawkone Date: Fri, 12 Jun 2026 16:49:31 -0700 Subject: [PATCH] fix(preview): add 60-second grace period before marking freshly booted servers as zombies to prevent aggressive 502 teardowns --- .../project/[projectId]/(home)/preview/page.tsx | 10 +++++++++- .../app/api/projects/[projectId]/anatomy/route.ts | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/vibn-frontend/app/[workspace]/project/[projectId]/(home)/preview/page.tsx b/vibn-frontend/app/[workspace]/project/[projectId]/(home)/preview/page.tsx index cebec62b..a360d0d6 100644 --- a/vibn-frontend/app/[workspace]/project/[projectId]/(home)/preview/page.tsx +++ b/vibn-frontend/app/[workspace]/project/[projectId]/(home)/preview/page.tsx @@ -126,6 +126,7 @@ export default function PreviewTab() { if (primaryRunning || primaryStarting) return; // already up or already starting ensureCalledRef.current = true; + setEnsureStatus("calling"); fetch(`/api/projects/${projectId}/dev-server/ensure`, { method: "POST", @@ -144,7 +145,14 @@ export default function PreviewTab() { } }) .catch(() => setEnsureStatus("error")); - }, [loading, anatomy, primaryRunning, primaryStarting, projectId]); + }, [ + loading, + anatomy, + primaryRunning, + primaryStarting, + projectId, + refreshKey, + ]); const [iframeSrc, setIframeSrc] = useState(null); const iframeDomRef = useRef(null); diff --git a/vibn-frontend/app/api/projects/[projectId]/anatomy/route.ts b/vibn-frontend/app/api/projects/[projectId]/anatomy/route.ts index a906ca66..4cf4b4eb 100644 --- a/vibn-frontend/app/api/projects/[projectId]/anatomy/route.ts +++ b/vibn-frontend/app/api/projects/[projectId]/anatomy/route.ts @@ -825,6 +825,14 @@ async function loadPreviews(projectId: string): Promise { ping.status === 504 || ping.status === 404 ) { + // Give freshly booted servers a 60-second grace period before murdering them. + // Traefik sometimes returns 502 for a few seconds right after the internal probe succeeds. + const ageMs = Date.now() - new Date(r.started_at).getTime(); + if (ageMs < 60000) { + activePreviews.push(r); + return; + } + console.warn( `[anatomy] Preview zombie detected for ${r.preview_url} (HTTP ${ping.status}). Marking stopped.`, );