NestJS / Advanced: lifetime and distributed-work evidence / Lesson 17
Observability, health and bounded shutdown
Measure safe operation outcomes and coordinate readiness, drain and resource release through explicit lifecycle ownership.
On this page
Lesson goals
- Distinguish telemetry, liveness, readiness and business success.
- Explain shutdown hooks without assuming a close call ends every task or process.
Collect stage evidence without copying private requests
Use safe controller/handler identifiers, result category, duration and bounded source counts rather than raw URLs, tokens or payloads. A successful HTTP status can coexist with a domain rejection if the API models that explicitly, so metrics need the application outcome too. Separate pool wait, handler work and downstream latency when diagnosis requires it. Concurrent spans overlap and inclusive parent spans contain child work; summing them can overstate elapsed time. Keep controlled correlation for detailed incidents instead of using high-cardinality user IDs as routine metric labels. Observability does not grant permission to retain every private input indefinitely.
Describe serving state and bounded probes
Health integrations can expose useful status, but choose what liveness and readiness mean for this deployment. A transient dependency outage need not imply that restarting a healthy process will fix it. Keep probes cheap, time-bounded and public-safe, and avoid dumping source configuration. The JSON note is a synthetic state contract, not a Terminus endpoint or an orchestrator setting. Readiness should stop admitting intended new work before dependencies close during drain. Verify ingress propagation separately; changing a local Boolean does not prove the upstream load balancer already stopped sending requests.
{"states":["starting","serving","draining","stopped"],"readyOnlyIn":"serving","probe":"safe-bounded-summary","drain":"deadline-and-owned-cleanup","sourceSecrets":"never-in-health-body"}
The record configures no health integration and sends no probe. It states assumptions to verify independently.
Enable and own lifecycle behavior deliberately
Nest shutdown hooks are tied to explicit application close or opted-in signal handling. Register the intended behavior and verify the selected versionโs hook order rather than relying on constructor order. Closing an application context does not necessarily terminate Node while intervals or other owned tasks remain active. Request-scoped and application-scoped resources also have different lifetimes. Stop admission, drain accepted work within a deadline, then release shared sources. Long-lived streams, message consumers and schedulers need their own coordinated policies so one subsystem does not continue producing work after another has closed its dependencies.
Test admission and completion as local invariants
The state model accepts one operation while serving, rejects new admission during drain and reaches stopped only after the accepted work count reaches zero. It sends no process signal and controls no real server. A real implementation needs exception-safe decrements, concurrent coordination and a forced-stop deadline. If that deadline expires during a write, preserve outcome uncertainty instead of reporting guaranteed rollback. The model is intentionally small so the desired ordering can be checked without operational side effects. It does not validate Nest hooks, Node signal behavior or actual source cleanup.
const state={phase:"serving",active:0};
function accept() {if (state.phase !== "serving") return false;state.active++;return true;}
console.assert(accept()); state.phase="draining";
console.assert(!accept() && state.active === 1);
state.active--; if (state.active === 0) state.phase="stopped";
console.assert(state.phase === "stopped");
One accepted operation finishes and no new operation enters after drain. No application is closed.
Tie deployment claims to executed evidence
Review logger integration, health exposure, source budgets, signal support and worker shutdown together with release and rollback artifacts. Multiple instances do not share in-memory session or replay maps automatically. Verify the intended lifecycle using synthetic workloads in an authorized isolated environment, not by terminating configured services during authoring. This course parses the policy and runs only the state model; it does not instantiate Terminus, register hooks, send signals, measure latency or run a load test. The next reviewer should be able to tell exactly which guarantees remain untested before adapting the design to a real system.
Common errors and fixes
A probe exposes source credentials
- Why it happens
- Detailed diagnostics were returned as public health data.
- How to fix it
- Return bounded safe status and protect internal evidence.
- Prevent it next time
- Assert exact public health fields.
A closed app leaves background work running
- Why it happens
- Context close was assumed to end every timer and task.
- How to fix it
- Give each long-lived resource an explicit stop owner.
- Prevent it next time
- Verify resources and process lifetime separately.
New requests enter after source cleanup
- Why it happens
- Admission and readiness changed too late.
- How to fix it
- Coordinate admission, drain and cleanup in dependency order.
- Prevent it next time
- Test late arrivals and in-flight work.
Check your understanding
1. Does app.close necessarily terminate the Node process?
Show worked solution
No. It performs the application shutdown sequence, but active intervals or independently owned background tasks can keep the process alive. Identify their owners and stop them under the lifecycle contract. Verify actual behavior in an isolated authorized integration rather than treating a shutdown log line as proof of full resource release.
2. Why distinguish readiness from liveness?
Show worked solution
One asks whether the process is functioning, while the other asks whether it should receive work under the deployment contract. Restarting a healthy process may not repair a shared dependency outage. Define bounded checks and rollout behavior so health policy supports recovery instead of amplifying it through unnecessary restarts.
Key takeaways
- Health and telemetry describe different facets of operation.
- Graceful shutdown requires explicit bounded ownership beyond decorators.