Operations 10 min read

Graceful Service Startup and Shutdown for Microservices with Spring Boot and Docker

This article explains how to implement graceful shutdown and startup for microservices using JVM shutdown hooks, Spring Boot's built‑in mechanisms, Docker stop signals, and external containers like Jetty, providing code examples and best‑practice recommendations for ensuring services deregister, reject traffic, and start only after health checks succeed.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Graceful Service Startup and Shutdown for Microservices with Spring Boot and Docker

For micro‑service architectures, graceful service up‑ and down‑times are essential to avoid exposing unhealthy instances and to ensure clean deregistration from registries.

Graceful Shutdown

JVM supports graceful termination via Runtime.getRuntime().addShutdownHook . A typical hook registers a thread that calls close() when the JVM receives a termination signal.

Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
        close();
    }
});

The hook is triggered in four common scenarios: normal program exit, System.exit() , Ctrl+C in a terminal, and kill <pid> . A forced kill -9 bypasses the hook, so it should be avoided.

Spring Boot already registers a shutdown hook that reacts to Ctrl+C or the SIGTERM signal ( kill -15 ). The core logic resides in AbstractApplicationContext and its registerShutdownHook method.

public void registerShutdownHook() {
    if (this.shutdownHook == null) {
        this.shutdownHook = new Thread() {
            public void run() {
                synchronized(AbstractApplicationContext.this.startupShutdownMonitor) {
                    AbstractApplicationContext.this.doClose();
                }
            }
        };
        Runtime.getRuntime().addShutdownHook(this.shutdownHook);
    }
}

public void destroy() {
    this.close();
}

public void close() {
    Object var1 = this.startupShutdownMonitor;
    synchronized(this.startupShutdownMonitor) {
        this.doClose();
        if (this.shutdownHook != null) {
            try {
                Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
            } catch (IllegalStateException var4) {
                ;
            }
        }
    }
}

protected void doClose() {
    if (this.active.get() && this.closed.compareAndSet(false, true)) {
        if (this.logger.isInfoEnabled()) {
            this.logger.info("Closing " + this);
        }
        LiveBeansView.unregisterApplicationContext(this);
        try {
            this.publishEvent(new ContextClosedEvent(this));
        } catch (Throwable var3) {
            this.logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", var3);
        }
        if (this.lifecycleProcessor != null) {
            try {
                this.lifecycleProcessor.onClose();
            } catch (Throwable var2) {
                this.logger.warn("Exception thrown from LifecycleProcessor on context close", var2);
            }
        }
        this.destroyBeans();
        this.closeBeanFactory();
        this.onClose();
        this.active.set(false);
    }
}

Developers can listen to the ContextClosedEvent to perform custom deregistration logic, such as removing the service from Zookeeper:

@Component
public class GracefulShutdownListener implements ApplicationListener
{

    @Override
    public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
        // deregistration logic
        zookeeperRegistry.unregister(mCurrentServiceURL);
        ...
    }
}

After deregistration, incoming traffic should be blocked (e.g., via a request filter) and let the framework’s fallback mechanisms handle the rejected calls.

Docker Shutdown

When a container is stopped with docker stop , Docker sends SIGTERM to PID 1 and waits 10 seconds before sending SIGKILL . Applications that handle SIGTERM can perform graceful shutdown within this window; the timeout can be adjusted with docker stop -t .

External Container (Jetty) Shutdown

For deployments using an external servlet container like Jetty, graceful shutdown can be achieved by invoking a provided RPC shutdown interface before the container stops, or simply by adding a kill -15 command to the container’s shutdown script.

Graceful Startup

Graceful startup is more complex because there is no default implementation. The principle is to expose the service only after the listening port is ready. In Spring Boot, developers can listen to ApplicationReadyEvent , which is published after the embedded container has started and the port is bound.

@Component
public class GracefulStartupListener implements ApplicationListener
{
    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        // registration logic – graceful startup
        apiRegister.register(urls);
        ...
    }
}

For external containers, a similar approach is required: the RPC framework must provide a “post‑start” hook that performs health checks and registers the service only after those checks succeed.

In summary, implementing graceful up‑ and down‑times involves leveraging JVM shutdown hooks, Spring Boot’s built‑in lifecycle events, Docker’s signal handling, and custom listeners to deregister services and block traffic during shutdown, while using startup events to ensure the service is only exposed after successful health verification.

dockerMicroservicesoperationsSpringBootGracefulShutdown
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.