Compare commits

...
2 Commits
Author SHA1 Message Date
Hermes 37b2630525 [grade=B] Fix DC-064: Bump Docker memory limit from 512m to 1g
CI / Security audit (push) Canceled after 0s
CI / Test & Lint (push) Canceled after 0s
512MB was too tight — container OOM-crashed during startup. Bumped to
1GB memory, 2GB swap, 2 CPUs. Production verified healthy on DNS2.
2026-08-12 06:16:37 -07:00
Hermes 306aff5ccf [grade=A] Fix DC production crash-loop: await listen()+close() in startup-validator port check
Root cause: net.createServer().listen(PORT).close() was fire-and-forget.
On a loaded host the port wasn't released before app.listen(PORT) ran in
server.js → EADDRINUSE 0.0.0.0:3001 → uncaughtException → process.exit(1)
→ Docker restart → same race → infinite crash loop (production outage on DNS2).

Fix: wrap both listen() and close() in a Promise and await it, so the
temporary server fully releases the port before validateStartupConfig()
returns. Listen errors are caught and converted to validation errors.

Codex grade A: urn:ump:xxfjvuy7fcwyetwnzo5h6zwnr3hqrsel44xa5ayrexnoksgp6qea
2026-08-12 06:13:38 -07:00
2 changed files with 14 additions and 3 deletions
@@ -74,11 +74,22 @@ async function validateStartupConfig({ log, CADDYFILE_PATH, SERVICES_FILE, CONFI
} }
// 3. Check if port is available // 3. Check if port is available
// CRITICAL: listen() and close() are async. If we fire-and-forget both
// (the old code), the kernel hasn't released the port by the time
// app.listen(PORT) runs in server.js → EADDRINUSE → crash loop.
// Await both via Promises so the port is truly free before we return.
const net = require('net'); const net = require('net');
const portCheckServer = net.createServer(); const portCheckServer = net.createServer();
try { try {
portCheckServer.listen(PORT, '0.0.0.0'); await new Promise((resolve, reject) => {
portCheckServer.close(); portCheckServer.once('error', reject);
portCheckServer.listen(PORT, '0.0.0.0', () => {
portCheckServer.close(() => {
portCheckServer.removeListener('error', reject);
resolve();
});
});
});
log.info('startup', `Port ${PORT} is available`); log.info('startup', `Port ${PORT} is available`);
} catch (error) { } catch (error) {
errors.push(`Port ${PORT} is already in use or cannot be bound`); errors.push(`Port ${PORT} is already in use or cannot be bound`);
+1 -1
View File
@@ -136,7 +136,7 @@ else
fi fi
docker run -d --restart unless-stopped --name ${CONTAINER_NAME} \ docker run -d --restart unless-stopped --name ${CONTAINER_NAME} \
--memory=512m --memory-swap=1g --cpus=1.5 \ --memory=1g --memory-swap=2g --cpus=2 \
--add-host=get.dashcaddy.net:194.233.88.206 \ --add-host=get.dashcaddy.net:194.233.88.206 \
--add-host=get2.dashcaddy.net:194.233.88.206 \ --add-host=get2.dashcaddy.net:194.233.88.206 \
--dns ${DNS_PRIMARY} \ --dns ${DNS_PRIMARY} \