How to Use a JVM Shutdown Hook to Drain In-Flight Requests
Reviewed by Gurusankar M. · Updated Aug 24, 2026
Short Answer
Runtime.getRuntime().addShutdownHook(thread) registers a thread the JVM runs during an orderly shutdown — SIGTERM, normal exit, or System.exit() — but never on SIGKILL or a crash. Use it to stop accepting new work, wait (with a bounded timeout) for in-flight requests to finish, then release resources, all inside whatever grace period your orchestrator gives the process before force-killing it.
On this page
Concept Made Simple
Coffee Chat Question
“How do you use a JVM shutdown hook to drain in-flight requests before exit?”
Remember It Faster
Mind Map Answer
A shutdown hook is a Thread registered via Runtime.getRuntime().addShutdownHook(hook) that the JVM starts the moment it begins an orderly shutdown — normal main() return, System.exit(), or a signal like SIGTERM (Ctrl+C, kill, a Kubernetes pod being terminated). It never runs on SIGKILL/kill -9 or a native crash — there's no orderly shutdown sequence for those to hook into.
- Runs on
- SIGTERM, System.exit(), normal exit
- Does NOT run on
- kill -9 / SIGKILL, native crash
- Typical use
- stop new work → drain in-flight → close resources
Kubernetes sends SIGTERM, then waits terminationGracePeriodSeconds (default 30s) before escalating to SIGKILL. A shutdown hook that takes longer than that window to drain gets killed mid-drain regardless of how correct its logic is — the grace period is a hard budget, not a suggestion.
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("SIGTERM received, draining...");
server.stopAcceptingNewConnections();
boolean drained = server.awaitInFlightRequests(Duration.ofSeconds(25));
if (!drained) log.warn("Forced shutdown with requests still in flight");
connectionPool.close();
}, "shutdown-hook"));Key takeaway: the hook's job is sequencing, not magic — stop the front door first so the in-flight count can only shrink, then wait for it to hit zero (bounded), then release resources. Skip the 'stop accepting new work' step and the hook can chase a moving target until the grace period runs out.
An uncaught exception inside a shutdown hook doesn't abort the shutdown sequence — the JVM runs every registered hook as its own thread, so one hook throwing just triggers its default UncaughtExceptionHandler (typically a stack trace on stderr) while the other registered hooks still run independently. That's easy to misread as "the hook must have failed silently and everything's fine" — in practice it means the specific cleanup step that threw never completed (a connection pool that didn't close, a flush that didn't happen), so a shutdown hook's own body should be wrapped in try/catch with explicit logging rather than left to rely on the default handler.
Think Beyond the Expected
What If?
Your shutdown hook takes 45s to drain but terminationGracePeriodSeconds is 30s — what happens?
Kubernetes sends SIGKILL at 30s regardless of the hook's progress — the JVM is killed mid-drain, and any requests still in flight at that instant are simply lost or reset from the client's perspective. Either shorten the drain budget to comfortably fit inside the grace period, or raise terminationGracePeriodSeconds to match the realistic worst case.
Real World
Every rolling deployment on Kubernetes or ECS depends on exactly this: a pod gets SIGTERM before it's removed from the load balancer's rotation and terminated, and a well-written shutdown hook is the difference between a clean deploy and a burst of connection-reset errors on every release.
Real Talk from Guru
I treat the shutdown hook's timeout as a real SLA, not a nice-to-have — I set it a few seconds under whatever the orchestrator's grace period is, log clearly when a shutdown was forced instead of clean, and alert on that log line. If forced shutdowns are common in practice, that's a signal the drain budget or the grace period needs to change, not something to quietly tolerate.
Interviewer's Expectation
Keywords they're listening for:
- addShutdownHook runs on SIGTERM/normal exit, not SIGKILL
- stop accepting new work before draining old work
- drain wait must be bounded by a timeout
- orchestrator grace period must exceed worst-case drain time
Common Mistakes
- Assuming the shutdown hook always runs (it doesn't on SIGKILL or a crash)
- No timeout on the drain wait, so the hook can block indefinitely on one stuck request
- terminationGracePeriodSeconds shorter than the realistic worst-case drain time
- Draining before stopping new connections, so the in-flight count never actually reaches zero
Best Practices
- Stop accepting new connections first, then drain existing ones
- Bound the drain wait with a timeout comfortably under the orchestrator's grace period
- Log (and alert on) forced/incomplete shutdowns for visibility
Follow-up Questions
- What signal does Kubernetes send before force-killing a pod?
- Why doesn't a shutdown hook run on kill -9?
- How do you make an HTTP server stop accepting new connections but finish existing ones?
- What happens if the shutdown hook itself throws an exception?
Continue Learning with AI
Take this question deeper with your favourite AI assistant. Pick a depth, copy the prompt, or open it directly — AI is your learning companion, not a shortcut.
Plain-language foundations
I'm preparing for a software engineering interview and want to understand this from scratch, as a beginner. Topic: Runtime (JVM) Interview question: "How do you use a JVM shutdown hook to drain in-flight requests before exit?" Please: 1. Explain the core idea in simple, plain language, using an everyday analogy. 2. Define any technical terms you use. 3. Walk through one small, concrete example. 4. Finish with a single sentence I can easily remember. Keep the tone friendly and assume I'm new to this topic.
Was this answer helpful?
Affiliate links
Tools for Your Developer Workspace
Equipment for a comfortable, productive setup.
As an Amazon Associate I earn from qualifying purchases.
- MonitorView on Amazon : BenQ EW2790U 27-inch Monitor (opens in a new tab)
BenQ EW2790U 27-inch Monitor
- LaptopView on Amazon : Acer Aspire One Laptop (opens in a new tab)
Acer Aspire One Laptop
- Office ChairView on Amazon : Wakefit Gravita Ergonomic Office Chair (opens in a new tab)
Wakefit Gravita Ergonomic Office Chair