Graceful Shutdown of Spring Boot Services and the Risks of Using kill -9
The article explains how the Linux kill command, especially kill -9, can abruptly terminate processes causing data inconsistency, and demonstrates safer alternatives for stopping Spring Boot applications—including kill -15, the built‑in shutdown script, Actuator endpoints, custom Tomcat connector shutdown, and @PreDestroy backup hooks—providing complete code examples.
kill sends signals to processes; the default SIGTERM (15) terminates gracefully, while SIGKILL (9) forces immediate termination. Using kill -9 on services such as a Spring Boot application can cause data loss similar to a sudden power outage, especially with non‑transactional storage engines.
Examples illustrate how a transaction on MyISAM can become inconsistent when a process is killed, and why distributed systems must avoid abrupt termination.
For a more graceful stop, kill -15 can be used. The article provides a simple controller that sleeps for 100 seconds and shows that sending kill -15 to the process interrupts the thread, causing an InterruptedException but still allowing cleanup.
@GetMapping(value = "/test")
public String test() {
log.info("test --- start");
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("test --- end");
return "test";
}Spring Boot also offers built‑in shutdown scripts (shutdown.sh/shutdown.bat) and the Actuator shutdown endpoint, which can be enabled in application.yml and invoked via HTTP.
server:
port: 9988
management:
endpoints:
web:
exposure:
include: shutdown
endpoint:
shutdown:
enabled: trueFor advanced control, the article introduces an ElegantShutdownConfig that customizes the Tomcat connector, pauses new requests, and waits up to a configurable timeout before forcing termination.
public class ElegantShutdownConfig implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
private volatile Connector connector;
private final int waitTime = 10;
@Override
public void customize(Connector connector) { this.connector = connector; }
@Override
public void onApplicationEvent(ContextClosedEvent event) {
connector.pause();
Executor executor = connector.getProtocolHandler().getExecutor();
if (executor instanceof ThreadPoolExecutor) {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
threadPoolExecutor.shutdown();
if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) {
System.out.println("Please try forceful shutdown");
}
}
}
}Finally, the article shows how to execute backup logic during shutdown using the @PreDestroy annotation in a Spring bean.
@Configuration
public class DataBackupConfig {
@PreDestroy
public void backData() {
System.out.println("Backing up data...");
}
}These techniques together provide a safe, graceful way to stop Spring Boot services without risking data corruption.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
