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
{
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.
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.