14 views
A rolling deploy that SIGKILLs in-flight POSTs is just a distributed partial-failure generator. Kubernetes preStop + terminationGracePeriodSeconds and ECS stop timeouts only help if your Node process actually stops accepting, drains HTTP, nacks queue ownership cleanly, and exits 0 before the grace window. The unfair advantage is a single shutdown orchestrator every entrypoint shares — not ad-hoc process.on('SIGTERM') snippets per service.
⚡ TL;DR: On SIGTERM: fail readiness immediately, stop queue consumers,server.close(), await in-flight with a deadline, flush telemetry, exit. Align K8spreStopsleep with ALB deregistration and ECSstopTimeout. Pair with Node Watch Mode in Staging and Lambda Alias Traffic Shifting for complementary deploy safety.
Graceful Shutdown for Node: production guidance
typescript
// src/shutdown.ts
import type { Server } from "node:http";
type Closer = () => Promise<void>;
const closers: Closer[] = [];
let shuttingDown = false;
export function onShutdown(fn: Closer) { closers.push(fn); }
export function isShuttingDown() { return shuttingDown; }
export function installShutdown(server: Server, budgetMs = 25_000) {
const run = async (signal: string) => {
if (shuttingDown) return;
shuttingDown = true;
console.log(JSON.stringify({ msg: "shutdown_start", signal }));
readiness.set(false); // ✅ ALB/K8s stop new traffic
const timer = setTimeout(() => {
console.error(JSON.stringify({ msg: "shutdown_timeout" }));
process.exit(1);
}, budgetMs);
try {
await new Promise<void>((res) => server.close(() => res()));
for (const c of closers) await c();
clearTimeout(timer);
process.exit(0);
} catch (err) {
console.error(err);
process.exit(1);
}
};
process.on("SIGTERM", () => void run("SIGTERM"));
process.on("SIGINT", () => void run("SIGINT"));
}
typescript
// ❌ Ignoring SIGTERM — K8s waits, then SIGKILL mid-request
// no handler at all
Stop consumers before HTTP drain finishes
typescript
// src/sqs-consumer.ts
import { onShutdown } from "./shutdown.js";
let running = true;
onShutdown(async () => {
running = false; // ✅ stop long-polling
await inFlight.drain(); // wait for handlers with AbortSignal
});
export async function loop(poll: () => Promise<Message[]>) {
while (running) {
const batch = await poll();
await Promise.all(batch.map((m) => handle(m, AbortSignal.timeout(10_000))));
}
}
Align platform timers
| Platform | Knob | Typical |
|---|---|---|
| K8s | preStop: sleep 5–10 |
Let endpoint slice propagate |
| K8s | terminationGracePeriodSeconds |
30–60 ≥ app budget |
| ALB | deregistration delay | Match preStop |
| ECS | stopTimeout |
≥ app budget + buffer |
| Node | shutdown budget | Leave 5s for SIGKILL margin |
yaml
# deployment.yaml excerpt
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10"]
terminationGracePeriodSeconds: 45
Closing checklist
✅ Dos – ✅ Fail readiness first on SIGTERM – ✅server.close() + await in-flight with deadline
– ✅ Stop queue/socket consumers explicitly
– ✅ Align preStop, deregistration, and stopTimeout
– ✅ Test with chaos: kill pods under load, measure 5xx
❌ Don’ts
– ❌ Don’t exit 0 while requests are still writing bodies
– ❌ Don’t set grace period shorter than app budget
– ❌ Don’t keep readiness green during drain
– ❌ Don’t forget open DB pools and telemetry flush
Related reading
- Node Watch Mode in Staging: Rapid Loops Without Leaking Watchers
- Blue/Green Stateful Workers: Drain In-Flight Jobs Before Old Tasks Die
- Lambda Alias Traffic Shifting: Automated Rollback Hooks That Fire
- Node undici Dispatcher Pools: Kill Keep-Alive Storms Under Spikes
Watch: 100 Days of AI on YouTube
Short videos from CheatCoders, one AI engineering topic per day.
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Claude Code vs Cursor vs GitHub Copilot: Choose by Workflow, and Set Up One Repo That Works With All Three
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- Css Animation Performance: Performance-Optimized Motion for Modern UIs
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Runtime Config for Coding Agents
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena for Coding Agents: Query Tool Audit Logs and Eval Traces on S3 Without a Warehouse
- AWS Batch for Coding Agents: Parallel Overnight PR Reviews and Long-Running Jobs Without Lambda Timeouts
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
