Stabilize Docker startup and runtime proxy

Reduce cold-start stalls by raising the default backend memory limit, bounding heavy feed concurrency, preserving non-empty startup caches, and refreshing working news feeds. Fix the Next API proxy for Docker control-plane writes by stripping unsupported hop/body headers and forwarding small request bodies safely. Keep the dashboard dynamic so production users do not get stuck on a cached startup shell.
This commit is contained in:
BigBodyCobain
2026-05-04 12:37:23 -06:00
parent 1e34fa53b2
commit 63043b32b5
10 changed files with 142 additions and 63 deletions
+13 -3
View File
@@ -26,6 +26,8 @@ const STRIP_REQUEST = new Set([
'transfer-encoding',
'upgrade',
'host',
'content-length',
'expect',
]);
// Headers that must not be forwarded back to the browser.
@@ -201,9 +203,10 @@ async function proxy(req: NextRequest, pathSegments: string[]): Promise<NextResp
cache: 'no-store',
};
if (!isBodyless) {
requestInit.body = req.body;
// Required for streaming request bodies in Node.js fetch
requestInit.duplex = 'half';
const body = await req.text();
if (body.length > 0) {
requestInit.body = body;
}
}
const maxAttempts = isBodyless ? 18 : 1;
let fetchError: unknown = null;
@@ -214,6 +217,13 @@ async function proxy(req: NextRequest, pathSegments: string[]): Promise<NextResp
break;
} catch (error) {
fetchError = error;
if (attempt >= maxAttempts) {
console.error('api proxy upstream fetch failed', {
method: req.method,
target: targetUrl.toString(),
error,
});
}
if (attempt >= maxAttempts) break;
await sleep(250);
}
+6
View File
@@ -8,6 +8,12 @@ export const metadata: Metadata = {
description: 'Advanced Geopolitical Risk Dashboard',
};
// The dashboard is a live local runtime, not a static landing page. If Next
// prerenders and caches the initial shell, Docker users can get stuck on the
// "prioritizing map feeds" markup before client polling ever hydrates.
export const dynamic = 'force-dynamic';
export const revalidate = 0;
export default function RootLayout({
children,
}: Readonly<{
+6 -3
View File
@@ -13,8 +13,8 @@ function buildCsp(nonce: string): string {
const directives = [
"default-src 'self'",
isDev
? `script-src 'self' 'unsafe-inline' 'unsafe-eval' 'nonce-${nonce}' blob:`
: `script-src 'self' 'unsafe-inline' 'nonce-${nonce}' blob:`,
? "script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:"
: "script-src 'self' 'unsafe-inline' blob:",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"img-src 'self' data: blob: https:",
isDev
@@ -35,7 +35,10 @@ function buildCsp(nonce: string): string {
export function middleware(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
// Forward nonce to server components via request header.
// Forward a nonce for future fully-wired CSP support. Do not include it in
// script-src until every Next inline bootstrap script receives the nonce;
// otherwise production hydration can fail and leave the app on the static
// "prioritizing map feeds" shell.
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-nonce', nonce);