mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 22:46:32 +00:00
5cb87a4df5
Three small gaps in how the process behaves at its edges: - An unhandled rejection or uncaught exception crashed the process with the stack on stderr only. index.ts now logs it to trek.log and runs the same orderly shutdown a SIGTERM gets, exiting with 1; a second fatal error during that shutdown exits at once. - /api/health/ready kept answering 200 while a SIGTERM was draining the process, so an orchestrator sent traffic for another probe period. A shutdown now marks the new ReadinessService first (and Nest's own shutdown hook marks it too), and the probe answers 503 from then on. - Node closes an idle keep-alive connection after 5 seconds while reverse proxies keep upstream connections for about a minute, which shows up as intermittent 502s. The server now keeps them for 65 seconds, configurable through HTTP_KEEP_ALIVE_TIMEOUT_MS (owned by the httpConfig token), with the headers timeout one second above.
50 lines
2.1 KiB
TypeScript
50 lines
2.1 KiB
TypeScript
/**
|
|
* Derive functions for the BOOT-STABLE values that Nest injects through a
|
|
* registerAs token (src/nest/app-config/tokens.ts) and nothing else reads.
|
|
*
|
|
* Every environment variable has exactly one owner. A variable derived here is
|
|
* owned by its token: `deriveAll()` (and so `readEnv()`) never reads it, which
|
|
* tests/unit/app-config/config-ownership.test.ts checks by recording the keys
|
|
* each side touches. A value that pre-container code needs, or that tests
|
|
* mutate mid-lifetime, belongs in derive.ts instead.
|
|
*/
|
|
import { parseBool, positiveIntOr } from './parsers';
|
|
|
|
/**
|
|
* Longer than the idle timeout of the common reverse proxies and load
|
|
* balancers (60 s), so the proxy closes an idle upstream connection before
|
|
* Node does. The other way round the proxy reuses a socket Node just closed
|
|
* and answers that request with a 502.
|
|
*/
|
|
export const DEFAULT_KEEP_ALIVE_TIMEOUT_MS = 65_000;
|
|
import type { RawEnv } from './derive';
|
|
|
|
/** What the pre-init Express layer and the HTTP server freeze when buildApp() runs. */
|
|
export function deriveHttpBoot(raw: RawEnv) {
|
|
// env.schema.ts accepts 0 as a valid hop count, so `|| 1` would quietly turn
|
|
// "trust nothing" into "trust one hop" and let a forged X-Forwarded-For through.
|
|
const trustProxyHops = Number.parseInt(raw.TRUST_PROXY ?? '', 10);
|
|
return {
|
|
trustProxyRaw: raw.TRUST_PROXY,
|
|
trustProxy: Number.isFinite(trustProxyHops) ? trustProxyHops : 1,
|
|
hstsIncludeSubdomains: parseBool(raw.HSTS_INCLUDE_SUBDOMAINS) === true,
|
|
/** How long the HTTP server keeps an idle keep-alive connection open. */
|
|
keepAliveTimeoutMs: positiveIntOr(raw.HTTP_KEEP_ALIVE_TIMEOUT_MS, DEFAULT_KEEP_ALIVE_TIMEOUT_MS),
|
|
};
|
|
}
|
|
|
|
/** Where the storage registry puts its conditional place-photo backend. */
|
|
export function deriveStorage(raw: RawEnv) {
|
|
return {
|
|
placePhotoDir: raw.TREK_PLACE_PHOTO_DIR,
|
|
};
|
|
}
|
|
|
|
/** One entry per token: the namespace it registers under and the function it derives with. */
|
|
export const BOOT_DERIVERS = {
|
|
http: deriveHttpBoot,
|
|
storage: deriveStorage,
|
|
} as const;
|
|
|
|
export type BootNamespace = keyof typeof BOOT_DERIVERS;
|