From 307663fa1f28965f44441c6bd938514c32b21216 Mon Sep 17 00:00:00 2001 From: Ragini-Microsoft Date: Wed, 6 May 2026 20:27:40 +0530 Subject: [PATCH 1/4] enhance admin API health check and improve error handling in proxy middleware --- scripts/post_deploy.py | 30 ++++++++++++++-- src/App/server/server.js | 75 +++++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 35 deletions(-) diff --git a/scripts/post_deploy.py b/scripts/post_deploy.py index 202d7ebeb..3ca8726e9 100644 --- a/scripts/post_deploy.py +++ b/scripts/post_deploy.py @@ -245,7 +245,7 @@ def get_api_headers(config: ResourceConfig) -> Dict[str, str]: async def check_admin_api_health(config: ResourceConfig, max_retries: int = 5, retry_delay: int = 10) -> bool: - """Check if the admin API is available with retry logic for cold starts.""" + """Check if the admin API is available with retry logic for cold starts and container restarts.""" print_step("Checking admin API health...") async with httpx.AsyncClient(timeout=30.0) as client: @@ -256,8 +256,32 @@ async def check_admin_api_health(config: ResourceConfig, max_retries: int = 5, r headers=get_api_headers(config) ) if response.status_code == 200: - print_success("Admin API is healthy") - return True + # Validate the response is actually from the backend admin API, + # not the frontend catch-all serving index.html + try: + data = response.json() + if data.get("status") == "healthy": + print_success("Admin API is healthy") + return True + else: + print_warning( + f"Attempt {attempt}/{max_retries}: Admin API returned unexpected JSON: {data}" + ) + except Exception: + # Response is not JSON. + # This means the API proxy is not forwarding requests to the backend. + content_preview = response.text[:200] + is_html = " { - // Disable buffering for streaming responses - if (proxyRes.headers['content-type']?.includes('text/event-stream')) { - res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); - res.setHeader('X-Accel-Buffering', 'no'); - res.setHeader('Connection', 'keep-alive'); - res.flushHeaders(); + const apiProxy = createProxyMiddleware({ + target: BACKEND_URL, + changeOrigin: true, + pathRewrite: { + '^/': '/api/' + }, + agent: httpAgent, + // Increase timeout for long-running requests (10 minutes) + proxyTimeout: 600000, + timeout: 600000, + // Support streaming responses (SSE) + onProxyRes: (proxyRes, req, res) => { + // Disable buffering for streaming responses + if (proxyRes.headers['content-type']?.includes('text/event-stream')) { + res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); + res.setHeader('X-Accel-Buffering', 'no'); + res.setHeader('Connection', 'keep-alive'); + res.flushHeaders(); + } + // Log response for debugging + console.log(`Proxy response: ${req.method} ${req.path} -> ${proxyRes.statusCode}`); + }, + onProxyReq: (proxyReq, req, res) => { + // Log request for debugging + console.log(`Proxy request: ${req.method} ${req.path}`); + }, + onError: (err, req, res) => { + console.error('Proxy error:', err.message); + if (!res.headersSent) { + res.status(502).json({ error: 'Backend service unavailable', details: err.message }); + } } - // Log response for debugging - console.log(`Proxy response: ${req.method} ${req.path} -> ${proxyRes.statusCode}`); - }, - onProxyReq: (proxyReq, req, res) => { - // Log request for debugging - console.log(`Proxy request: ${req.method} ${req.path}`); - }, - onError: (err, req, res) => { - console.error('Proxy error:', err.message); - if (!res.headersSent) { - res.status(502).json({ error: 'Backend service unavailable', details: err.message }); - } - } -})); + }); + app.use('/api', apiProxy); +} else { + // When BACKEND_URL is not set, return a clear error for API requests + // instead of letting them fall through to the SPA catch-all (which returns index.html with 200) + app.use('/api', (req, res) => { + res.status(503).json({ + error: 'Backend not configured', + message: 'BACKEND_URL environment variable is not set. The API proxy is not available.', + }); + }); } + // Serve static files from the build directory app.use(express.static(path.join(__dirname, 'static'))); From 1abee3286044534a29fdef8d67e326a8ae8eb8da Mon Sep 17 00:00:00 2001 From: Ragini-Microsoft Date: Wed, 6 May 2026 21:50:23 +0530 Subject: [PATCH 2/4] increase retry count and delay for admin API health check as in WAF container needs time to restart --- scripts/post_deploy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/post_deploy.py b/scripts/post_deploy.py index 3ca8726e9..48e19c666 100644 --- a/scripts/post_deploy.py +++ b/scripts/post_deploy.py @@ -244,7 +244,7 @@ def get_api_headers(config: ResourceConfig) -> Dict[str, str]: return headers -async def check_admin_api_health(config: ResourceConfig, max_retries: int = 5, retry_delay: int = 10) -> bool: +async def check_admin_api_health(config: ResourceConfig, max_retries: int = 12, retry_delay: int = 15) -> bool: """Check if the admin API is available with retry logic for cold starts and container restarts.""" print_step("Checking admin API health...") From 9f5eb06adcc3b1c7b377f7aa3bfd228170e9e0bd Mon Sep 17 00:00:00 2001 From: Ragini-Microsoft Date: Thu, 7 May 2026 10:10:24 +0530 Subject: [PATCH 3/4] adjust retry count and delay for admin API health check to improve reliability --- scripts/post_deploy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/post_deploy.py b/scripts/post_deploy.py index 48e19c666..da005eb14 100644 --- a/scripts/post_deploy.py +++ b/scripts/post_deploy.py @@ -244,7 +244,7 @@ def get_api_headers(config: ResourceConfig) -> Dict[str, str]: return headers -async def check_admin_api_health(config: ResourceConfig, max_retries: int = 12, retry_delay: int = 15) -> bool: +async def check_admin_api_health(config: ResourceConfig, max_retries: int = 8, retry_delay: int = 20) -> bool: """Check if the admin API is available with retry logic for cold starts and container restarts.""" print_step("Checking admin API health...") From baefa82d9a43dbd6a0c1771848338c33b204b632 Mon Sep 17 00:00:00 2001 From: Ragini-Microsoft Date: Thu, 7 May 2026 11:54:05 +0530 Subject: [PATCH 4/4] refine exception handling in admin API health check to catch specific JSON errors --- scripts/post_deploy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/post_deploy.py b/scripts/post_deploy.py index da005eb14..72e8d0a67 100644 --- a/scripts/post_deploy.py +++ b/scripts/post_deploy.py @@ -267,7 +267,7 @@ async def check_admin_api_health(config: ResourceConfig, max_retries: int = 8, r print_warning( f"Attempt {attempt}/{max_retries}: Admin API returned unexpected JSON: {data}" ) - except Exception: + except (ValueError, json.JSONDecodeError): # Response is not JSON. # This means the API proxy is not forwarding requests to the backend. content_preview = response.text[:200]