mirror of
https://github.com/dtzp555-max/olp.git
synced 2026-07-22 05:25:09 +00:00
fix(server): add process-level crash handlers unhandledRejection/uncaughtException/clientError (P1)
Registers three crash-prevention handlers at module level so they are
installed before the first request arrives. These are no-ops on the
happy-path /v1/chat/completions request cycle.
process.on('unhandledRejection', ...) — logs and stays alive
process.on('uncaughtException', ...) — logs and stays alive
server.on('clientError', ...) — destroys the broken socket
process.exit is intentionally NOT called in unhandledRejection /
uncaughtException — the daemon logs the event and continues serving. The
clientError handler destroys the socket to release the file descriptor; if
left open, broken sockets from mid-upload client aborts or malformed HTTP
headers accumulate and exhaust fd limits.
server.on('clientError') is attached inside createOlpServer() (the factory
function) so it is present on every server instance, including test servers
created via the factory — enabling the 45f listener-count assertion.
Authority (ALIGNMENT.md Rule 1 + Rule 5):
Entry-surface scope — OpenAI Chat Completions API contract unchanged.
https://platform.openai.com/docs/api-reference/chat
happy-path /v1/chat/completions is unaffected; these handlers only fire on
low-level TCP/parse errors or unhandled promises outside the request cycle.
Port source: OCP server.mjs:2134-2146.
Tests (Suite 45):
45a–45c: Task A — stdin EPIPE guard fires and logs stdin_write_error in
anthropic, codex, and mistral providers (mock spawn with EventEmitter
stdin that emits EPIPE).
45d: process.listenerCount('unhandledRejection') >= 1
45e: process.listenerCount('uncaughtException') >= 1
45f: server created by createOlpServer() has a clientError listener >= 1
Total test count: 819 pass / 0 fail (813 pre-existing + 6 new).
CHANGELOG.md: adds Unreleased entry for both P1 crash-hardening fixes per
release_kit phase_rolling_mode policy (Phase 7 closed at v0.7.0; D-day
commits land under Unreleased until Phase 8 close).
Co-Authored-By: Claude <claude-sonnet-4-6> <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude <claude-sonnet-4-6> <noreply@anthropic.com>
parent
a503441ea3
commit
422512d2b2
+26
-1
@@ -2383,6 +2383,23 @@ async function router(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Process-level crash handlers ─────────────────────────────────────────
|
||||
// Prevent unhandled async rejections and synchronous exceptions from crashing
|
||||
// the daemon. Registered once at module level so they are installed before
|
||||
// the first request arrives. These are no-ops on the happy path.
|
||||
// Port of OCP server.mjs:2134-2146.
|
||||
// Authority: OpenAI Chat Completions entry-surface contract unchanged
|
||||
// (https://platform.openai.com/docs/api-reference/chat); happy-path
|
||||
// /v1/chat/completions is unaffected — these handlers only fire on
|
||||
// low-level TCP/parse errors or unhandled promises outside the request cycle.
|
||||
// Note: process.exit is intentionally NOT called — log only, daemon stays alive.
|
||||
process.on('unhandledRejection', (reason) =>
|
||||
logEvent('error', 'unhandled_rejection', { reason: String(reason) })
|
||||
);
|
||||
process.on('uncaughtException', (err) =>
|
||||
logEvent('error', 'uncaught_exception', { error: err && err.message, stack: err && err.stack })
|
||||
);
|
||||
|
||||
// ── Server factory + main guard ───────────────────────────────────────────
|
||||
//
|
||||
// Factory pattern: `createOlpServer()` returns an http.Server bound to the
|
||||
@@ -2392,7 +2409,15 @@ async function router(req, res) {
|
||||
// import-time side effects when tests pull in server.mjs.
|
||||
|
||||
export function createOlpServer() {
|
||||
return createServer(router);
|
||||
const srv = createServer(router);
|
||||
// Destroy the socket on low-level HTTP parse errors (client abort mid-upload,
|
||||
// malformed HTTP header, etc.) so broken connections don't crash the daemon.
|
||||
// Port of OCP server.mjs:2144-2146.
|
||||
// Authority: OpenAI Chat Completions entry-surface contract unchanged
|
||||
// (https://platform.openai.com/docs/api-reference/chat); happy-path /v1/chat/completions
|
||||
// is unaffected — clientError only fires on pre-request TCP-level failures.
|
||||
srv.on('clientError', (err, socket) => { try { socket.destroy(); } catch {} });
|
||||
return srv;
|
||||
}
|
||||
|
||||
export { router, loadedProviders, VERSION };
|
||||
|
||||
Reference in New Issue
Block a user