Skip to content

Add liveness/readiness probes, a locked-down CORS allowlist, and graceful shutdown - #1910

Merged
yusuftomilola merged 2 commits into
DistinctCodes:mainfrom
limxiy:feature/cors-healthcheck-env-graceful-shutdown
Sep 25, 2026
Merged

yusuftomilola merged 2 commits into
DistinctCodes:mainfrom
limxiy:feature/cors-healthcheck-env-graceful-shutdown

Conversation

@limxiy

@limxiy limxiy commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes four issues assigned to this account, all in the backend.

Orchestrator health probes (#1792)
Adds a HealthModule built on @nestjs/terminus:

  • GET /health — liveness. Dependency-free; it must not inspect the database, because a database blip must not cause an orchestrator to kill an otherwise healthy pod.
  • GET /health/ready — readiness. A real TypeOrmHealthIndicator.pingCheck with a bounded, configurable timeout; Terminus turns an unreachable database into a 503 automatically.

JwtAuthGuard is intentionally absent so probes and health checkers work; the global ThrottlerGuard still applies. The pre-existing combined dependency view moved to GET /health/dependencies so it no longer shadows the new liveness route — this is a route change: anything that previously used GET /health as a dependency check should use /health/ready or /health/dependencies.

CORS allowlist (#1793)
The app never called enableCors, so the implicit allow-all applied to a credentialed API. CORS is now an explicit per-environment allowlist driven by CORS_ORIGINS:

  • Requests with no Origin header (same-origin/non-browser clients, curl, probes) are allowed.
  • Present origins must match an exact allowlist entry; anything else is rejected with an error rather than silently.
  • Development/test fall back to the two local frontend origins; production falls closed to an empty allowlist and logs a warning, so a misconfigured deploy denies cross-origin traffic instead of allowing it.

backend/.env.example audit (#1791)
Enumerated every variable the backend actually reads (process.env.* and every ConfigService.get* string key across auth, database, payments and adapters, Soroban/Stellar, wallets, credits, retention, common, and main.ts) and diffed it against the file. The result is an annotated source-of-truth: each section states which file reads it, variables present in the file but read nowhere are marked [RESERVED/UNUSED] rather than silently deleted, and nothing the code reads is left undocumented.

Graceful shutdown (#1790)
SIGTERM/SIGINT now drain instead of dropping in-flight requests: stop accepting connections (server.close() + closeIdleConnections()), await app.close() so Nest lifecycle hooks run, and force-exit only if a configurable watchdog expires. Re-entrant signals are ignored rather than running the hooks twice. The logic lives in an exported, injectable helper so it is unit-testable without spawning a process.

Configuration

Variable Default Purpose
CORS_ORIGINS dev/test: local origins; prod: empty (deny all) Exact allowed browser origins, comma-separated
HEALTH_CHECK_TIMEOUT_MS 3000 (capped at 30000) Readiness DB ping timeout
GRACEFUL_SHUTDOWN_TIMEOUT_MS 30000 Drain budget before forced exit

Testing

Per the task constraints, no install, build, lint, or test run was performed — the maintainer runs those manually.

New specs: common/cors.spec.ts, common/graceful-shutdown.spec.ts, health/health.controller.spec.ts.
backend/package-lock.json is intentionally not regenerated; @nestjs/terminus is declared in package.json and the lockfile needs an npm install before npm ci will succeed.

New dependency

@nestjs/terminus (NestJS 10-compatible line).

Closing issues

Closes #1793
Closes #1792
Closes #1791
Closes #1790

…aceful shutdown

Adds a Terminus-based HealthModule: GET /health is a dependency-free liveness probe and GET /health/ready is a readiness probe that pings TypeORM with a bounded timeout and reports 503 when the database is unreachable. The pre-existing combined dependency view moves to GET /health/dependencies so it no longer shadows the liveness route.

Locks CORS down to an explicit per-environment allowlist driven by CORS_ORIGINS. Development and test fall back to the two local frontend origins; production falls closed to an empty allowlist and logs a warning, so a misconfigured deploy denies cross-origin traffic instead of allowing it. Credentialed requests are still supported.

Adds bounded, idempotent SIGTERM/SIGINT handling that closes the HTTP server, drains idle connections, runs Nest lifecycle hooks, and force-exits only after a configurable watchdog expires.

Audits backend/.env.example against every variable the source actually reads, documents where each is read, and marks the reserved/unused entries explicitly.

Closes DistinctCodes#1793
Closes DistinctCodes#1792
Closes DistinctCodes#1791
Closes DistinctCodes#1790
@vercel

vercel Bot commented Sep 24, 2026

Copy link
Copy Markdown

@limxiy is attempting to deploy a commit to the naijabuz's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Sep 24, 2026

Copy link
Copy Markdown

@limxiy Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

…eck-env-graceful-shutdown

# Conflicts:
#	backend/.env.example
#	backend/src/main.ts
@yusuftomilola
yusuftomilola merged commit 2c78632 into DistinctCodes:main Sep 25, 2026
2 of 8 checks passed

This branch had an error being deployed

1 failed deployment
Preview — c0f4e858 Deployed Sep 25, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants