Graceful Shutdown of Spring Cloud Microservices with Nacos – Practical Guide
This article explains why graceful shutdown is needed for Spring Cloud microservices using Nacos, compares several shutdown approaches—including kill command, /shutdown, /pause, and /service‑registry endpoints—provides configuration snippets, curl commands, and code examples, and highlights their limitations and best‑practice recommendations.
Introduction
In distributed systems that rely on service registries such as Nacos or Eureka, client instances cache the list of available services to satisfy the CAP principle’s availability requirement. When a service is stopped normally, the registry is notified, but the cached lists on clients become stale for a few seconds, causing requests to be routed to a shutting‑down instance and potentially slowing down user responses. A graceful shutdown strategy avoids this problem by ensuring traffic is drained before the instance disappears from the registry.
Method 1: Using the kill Command
Spring Cloud registers a shutdown hook that automatically deregisters the instance from the registry when the JVM exits. The process can be stopped with a normal kill command: kill <em>JavaProcessId</em> The hook works for normal exits, System.exit(), or Ctrl+C, but not for kill -9 or sudden crashes. Although the instance is deregistered, the registry’s client cache may still retain the address for the default Nacos cache timeout (5 seconds), so this method does not fully solve the stale‑cache issue.
Method 2: Exposing the /shutdown Endpoint
Spring Boot Actuator provides a /shutdown endpoint that triggers the same shutdown hook. To enable it, add the actuator starter and configure exposure:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> management:
endpoint:
shutdown:
enabled: true
endpoints:
web:
exposure:
include: shutdownThen invoke the endpoint, for example:
curl -X POST http://<em>service-host</em>/actuator/shutdownBecause it also relies on the shutdown hook, the client‑cache delay remains, so this approach is not recommended for true graceful shutdown.
Method 3: Using the /pause Endpoint
Spring Boot Actuator also offers a /pause endpoint that changes the health status of an instance from UP to DOWN without terminating the JVM. Enable it as follows:
management:
endpoint:
pause:
enabled: true
restart:
enabled: true
endpoints:
web:
exposure:
include: pause,restartSend a POST request to pause the service:
curl -X POST http://<em>service-host</em>/actuator/pauseIn practice this endpoint has inconsistent behavior across Spring Boot versions; it does not work reliably in 2.4.x and later because the underlying lifecycle handling changed. Therefore the article advises against using /pause for production shutdowns, though the idea of marking the instance as down before termination is still valuable.
Method 4: Using the /service‑registry Endpoint
Spring Cloud defines a generic ServiceRegistryEndpoint that can set the registration status of any supported registry. Enable the endpoint:
management:
endpoints:
web:
exposure:
include: service-registry
base-path: /actuator
endpoint:
serviceregistry:
enabled: trueAfter enabling, the actuator’s /actuator page lists the new endpoint. You can change the instance status with a POST request:
curl -X "POST" "http://localhost:8081/actuator/serviceregistry?status=DOWN" \
-H "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8"Before the call the Nacos console shows the instance as "UP"; after the call it appears as "DOWN" (or "上线"/"下线" in the UI), confirming that the instance has been deregistered. The following images illustrate the UI before and after the operation:
The underlying implementation is a simple Spring Boot endpoint:
@Endpoint(id = "serviceregistry")
public class ServiceRegistryEndpoint {
private final ServiceRegistry serviceRegistry;
private Registration registration;
public ServiceRegistryEndpoint(ServiceRegistry<?> serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
public void setRegistration(Registration registration) {
this.registration = registration;
}
@WriteOperation
public ResponseEntity<?> setStatus(String status) {
Assert.notNull(status, "status may not be null");
if (this.registration == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("no registration found");
}
this.serviceRegistry.setStatus(this.registration, status);
return ResponseEntity.ok().build();
}
@ReadOperation
public ResponseEntity<?> getStatus() {
if (this.registration == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("no registration found");
}
return ResponseEntity.ok().body(this.serviceRegistry.getStatus(this.registration));
}
}This endpoint works with any registry that implements Spring Cloud’s ServiceRegistry interface, so the same technique applies to Eureka, Consul, etc.
Conclusion
Graceful shutdown for Spring Cloud microservices requires more than simply stopping the JVM; the service must be marked down in the registry and given enough time for client caches to refresh. The /service‑registry endpoint provides the most reliable way to achieve this across different registries, while the /shutdown and /pause endpoints have notable limitations. Implementing a custom controller that first deregisters the instance and then waits (e.g., 5 seconds) before terminating the process is a practical pattern for production environments.
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.
Senior Brother's Insights
A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.
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.
