From 5b7e343139677844b1a544d178047538e36fd101 Mon Sep 17 00:00:00 2001 From: DocFast Bot Date: Mon, 16 Feb 2026 16:10:15 +0000 Subject: [PATCH] build: compile dist for sitemap, favicon, and graceful shutdown changes --- dist/index.js | 52 ++++++++++++++++++++++++++++++++++------ dist/services/browser.js | 2 ++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/dist/index.js b/dist/index.js index 416df55..f0d0721 100644 --- a/dist/index.js +++ b/dist/index.js @@ -20,7 +20,7 @@ import { pdfRateLimitMiddleware, getConcurrencyStats } from "./middleware/pdfRat import { initBrowser, closeBrowser } from "./services/browser.js"; import { loadKeys, getAllKeys } from "./services/keys.js"; import { verifyToken, loadVerifications } from "./services/verification.js"; -import { initDatabase } from "./services/db.js"; +import { initDatabase, pool } from "./services/db.js"; const app = express(); const PORT = parseInt(process.env.PORT || "3100", 10); app.use(helmet({ crossOriginResourcePolicy: { policy: "cross-origin" } })); @@ -152,6 +152,12 @@ ${apiKey ? ` } // Landing page const __dirname = path.dirname(fileURLToPath(import.meta.url)); +// Favicon route +app.get("/favicon.ico", (_req, res) => { + res.setHeader('Content-Type', 'image/svg+xml'); + res.setHeader('Cache-Control', 'public, max-age=604800'); + res.sendFile(path.join(__dirname, "../public/favicon.svg")); +}); app.use(express.static(path.join(__dirname, "../public"), { maxAge: "1d", etag: true, @@ -270,14 +276,46 @@ async function start() { await loadUsageData(); await initBrowser(); logger.info(`Loaded ${getAllKeys().length} API keys`); - app.listen(PORT, () => logger.info(`DocFast API running on :${PORT}`)); - const shutdown = async () => { - logger.info("Shutting down..."); - await closeBrowser(); + const server = app.listen(PORT, () => logger.info(`DocFast API running on :${PORT}`)); + let shuttingDown = false; + const shutdown = async (signal) => { + if (shuttingDown) + return; + shuttingDown = true; + logger.info(`Received ${signal}, starting graceful shutdown...`); + // 1. Stop accepting new connections, wait for in-flight requests (max 10s) + await new Promise((resolve) => { + const forceTimeout = setTimeout(() => { + logger.warn("Forcing server close after 10s timeout"); + resolve(); + }, 10_000); + server.close(() => { + clearTimeout(forceTimeout); + logger.info("HTTP server closed (all in-flight requests completed)"); + resolve(); + }); + }); + // 2. Close Puppeteer browser pool + try { + await closeBrowser(); + logger.info("Browser pool closed"); + } + catch (err) { + logger.error({ err }, "Error closing browser pool"); + } + // 3. Close PostgreSQL connection pool + try { + await pool.end(); + logger.info("PostgreSQL pool closed"); + } + catch (err) { + logger.error({ err }, "Error closing PostgreSQL pool"); + } + logger.info("Graceful shutdown complete"); process.exit(0); }; - process.on("SIGTERM", shutdown); - process.on("SIGINT", shutdown); + process.on("SIGTERM", () => shutdown("SIGTERM")); + process.on("SIGINT", () => shutdown("SIGINT")); } start().catch((err) => { logger.error({ err }, "Failed to start"); diff --git a/dist/services/browser.js b/dist/services/browser.js index 7516106..38e99c3 100644 --- a/dist/services/browser.js +++ b/dist/services/browser.js @@ -196,6 +196,7 @@ export async function closeBrowser() { export async function renderPdf(html, options = {}) { const { page, instance } = await acquirePage(); try { + await page.setJavaScriptEnabled(false); const result = await Promise.race([ (async () => { await page.setContent(html, { waitUntil: "domcontentloaded", timeout: 15_000 }); @@ -222,6 +223,7 @@ export async function renderPdf(html, options = {}) { export async function renderUrlPdf(url, options = {}) { const { page, instance } = await acquirePage(); try { + await page.setJavaScriptEnabled(false); const result = await Promise.race([ (async () => { await page.goto(url, {