diff --git a/website/server/Dockerfile b/website/server/Dockerfile index 27b529d77..73a81133d 100644 --- a/website/server/Dockerfile +++ b/website/server/Dockerfile @@ -44,11 +44,20 @@ COPY --from=builder /app/dist-bundled ./dist-bundled COPY --from=builder /app/node_modules/tinypool ./node_modules/tinypool COPY --from=builder /app/node_modules/tiktoken ./node_modules/tiktoken +# Copy warmup script for compile cache generation +COPY --from=builder /app/warmup.mjs ./warmup.mjs + # Set environment variables for bundled mode +# NODE_COMPILE_CACHE enables V8 compile cache to reduce cold start latency ENV NODE_ENV=production \ PORT=8080 \ REPOMIX_WORKER_PATH=/app/dist-bundled/server.mjs \ - REPOMIX_WASM_DIR=/app/dist-bundled/wasm + REPOMIX_WASM_DIR=/app/dist-bundled/wasm \ + NODE_COMPILE_CACHE=/app/.compile-cache + +# Generate compile cache at build time +# This pre-compiles all modules so cold starts use cached compiled code +RUN node warmup.mjs # Expose port EXPOSE 8080 diff --git a/website/server/src/index.ts b/website/server/src/index.ts index 670a2306a..fd3511f0d 100644 --- a/website/server/src/index.ts +++ b/website/server/src/index.ts @@ -1,3 +1,4 @@ +import module from 'node:module'; import { serve } from '@hono/node-server'; import { Hono } from 'hono'; import { compress } from 'hono/compress'; @@ -22,14 +23,20 @@ const isTinypoolWorker = (): boolean => { return tinypoolState?.isTinypoolWorker ?? false; }; -// Skip server initialization if running as a Tinypool worker -if (!isTinypoolWorker()) { +// Check if running in warmup mode (for compile cache generation) +const isWarmupMode = (): boolean => { + return process.env.WARMUP_MODE === 'true'; +}; + +// Skip server initialization if running as a Tinypool worker or in warmup mode +if (!isTinypoolWorker() && !isWarmupMode()) { const API_TIMEOUT_MS = 35_000; // Log server metrics on startup logInfo('Server starting', { metrics: { processConcurrency: getProcessConcurrency(), + compileCacheDir: module.getCompileCacheDir(), }, }); diff --git a/website/server/warmup.mjs b/website/server/warmup.mjs new file mode 100644 index 000000000..8d887c267 --- /dev/null +++ b/website/server/warmup.mjs @@ -0,0 +1,29 @@ +/** + * Warmup script for Node.js compile cache generation. + * + * This script is executed during Docker build to pre-generate V8 compile cache. + * By loading all modules at build time, subsequent cold starts will use + * the cached compiled code, reducing startup latency. + * + * @see https://nodejs.org/api/module.html#moduleenablecompilecachedir + */ + +import { enableCompileCache, flushCompileCache } from 'node:module'; + +// Enable compile cache (uses NODE_COMPILE_CACHE env var for directory) +enableCompileCache(); + +// Set warmup mode to prevent server from actually starting +process.env.WARMUP_MODE = 'true'; + +// Import the server module to trigger compilation of all dependencies +await import('./dist-bundled/server.mjs'); + +// Flush cache to disk immediately (default is on process exit) +flushCompileCache(); + +console.log('Compile cache generated successfully'); + +// Explicitly exit the process +// Some modules (like winston/logging) may keep the event loop alive +process.exit(0);