Skip to content

feat(server): pin + expose HTTP server timeouts#703

Merged
rmyndharis merged 1 commit into
mainfrom
feat/server-http-timeouts
Jul 12, 2026
Merged

feat(server): pin + expose HTTP server timeouts#703
rmyndharis merged 1 commit into
mainfrom
feat/server-http-timeouts

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

What

The HTTP server now runs with explicitly pinned requestTimeout / headersTimeout / keepAliveTimeout, exposed as env vars and logged at boot — previously it used Node's implicit defaults.

Why

Node's defaults (300s/60s/5s) are reasonable but invisible and not tunable. An operator behind a reverse proxy has no knob for the request lifecycle, and a misconfiguration (e.g. headersTimeout < keepAliveTimeout, which Node warns about and self-corrects invisibly) is silent. This makes the values explicit, observable, and adjustable.

How

  • New config namespace http (configuration.ts): REQUEST_TIMEOUT_MS (300000), HEADERS_TIMEOUT_MS (65000), KEEPALIVE_TIMEOUT_MS (5000).
  • applyHttpTimeouts(server, cfg) (config/http-timeouts.ts) writes the three fields onto the http.Server and normalizes headersTimeout to keepAliveTimeout + 1000 when misconfigured, returning the resolved values. Extracted as a pure helper so the rule is unit-tested without booting the app.
  • main.ts applies it after NestFactory.create, before app.listen, and logs the applied values.
  • env.validation.ts requires the three to be positive integers (a 0 would silently disable the bound).

Test plan

  • New http-timeouts.spec.ts (4 cases): writes the fields, keeps a valid headers value, auto-bumps a misconfigured one, reports resolved values. TDD: written first, watched fail against a stub, then implemented.
  • Full unit suite green (2290 passed) — the three new env checks run at AppModule init via validateEnv, so any booting spec exercises them.

No change to default behavior (defaults match Node 22); headersTimeout default rises 60s → 65s to stay above keepAliveTimeout.

The HTTP server previously ran on Node's implicit requestTimeout /
headersTimeout / keepAliveTimeout defaults -- bounded but not
operator-tunable and invisible at boot. Pin them explicitly from
REQUEST_TIMEOUT_MS / HEADERS_TIMEOUT_MS / KEEPALIVE_TIMEOUT_MS (defaults
300s / 65s / 5s, matching Node 22 while keeping headersTimeout a second
above keepAliveTimeout, which Node requires), log the applied values, and
validate the three as positive integers at boot. The normalization rule
(headers > keepAlive) lives in a unit-tested helper rather than the
bootstrap script.
@rmyndharis rmyndharis merged commit 7aafa66 into main Jul 12, 2026
3 of 4 checks passed
@rmyndharis rmyndharis deleted the feat/server-http-timeouts branch July 12, 2026 04:10
rmyndharis added a commit that referenced this pull request Jul 12, 2026
1. getContactStatus(contactId) 500'd on the common case: a contact with no
   active 24h story resolves to an "empty" Broadcast (the Broadcast
   constructor only _patches when data is truthy, so id/msgs/getContact are
   undefined), and collectStatuses dereferenced them. Guard the empty
   Broadcast in getContactStatus (return []) + skip no-msgs Broadcasts in the
   plural path. +2 specs (no-story singular + empty-in-plural).

2. HTTP server timeouts (#703) were written onto the Express APPLICATION
   (getHttpAdapter().getInstance()) instead of the http.Server, so the
   REQUEST/HEADERS/KEEPALIVE_TIMEOUT_MS assignments were inert while the boot
   log claimed they applied. Target app.getHttpServer() (the real server) +
   a comment so the wrong target isn't reintroduced.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant