DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
View Events Video Library
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Migrate, Modernize and Build Java Web Apps on Azure: This live workshop will cover methods to enhance Java application development workflow.

Modern Digital Website Security: Prepare to face any form of malicious web activity and enable your sites to optimally serve your customers.

Kubernetes in the Enterprise: The latest expert insights on scaling, serverless, Kubernetes-powered AI, cluster security, FinOps, and more.

A Guide to Continuous Integration and Deployment: Learn the fundamentals and understand the use of CI/CD in your apps.

Related

  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)
  • Java, Spring Boot, and MongoDB: Performance Analysis and Improvements
  • Spring Boot Secured By Let's Encrypt
  • How To Build Web Service Using Spring Boot 2.x

Trending

  • Big Data Empowers IoT: Challenges and Solutions
  • Anatomy of a High Availability Kubernetes Cluster
  • Improving Unit Test Maintainability
  • Decompose Legacy System Into Microservices: Part 2
  1. DZone
  2. Coding
  3. Frameworks
  4. Graceful Shutdown Spring Boot Applications

Graceful Shutdown Spring Boot Applications

Want to find out how to gracefully shutdown your Spring Boot apps? Click here to learn more about shutting down Spring Boot apps and installing newer versions.

Marcos Barbero user avatar by
Marcos Barbero
DZone Core CORE ·
Updated Jul. 10, 18 · Tutorial
Like (34)
Save
Tweet
Share
83.3K Views

Join the DZone community and get the full member experience.

Join For Free

This guide walks through the process gracefully shutting down a Spring Boot application.

The implementation of this blog post is originally created by Andy Wilkinson and adapted by me to Spring Boot 2. The code is based on this    GitHub comment.

Introduction

A lot of developers and architects discuss the application design, traffic load, frameworks, and patterns to apply to code, but very few of them are discussing the shutdown phase.

Let’s consider this scenario — there’s an application that has a long blocking process. Along with that, this app needs to be shut down and replaced with a newer version. Wouldn't it be nice if, instead of killing all the connections, it just gracefully waited to finish before the shutdown?

That’s what we are going to cover in this guide!

Pre-requisites

  • JDK 1.8
  • A text editor or your favorite IDE
  • Maven 3.0+

Spring Boot, Tomcat

To make this feature work, the first step is to implement the TomcatConnectorCustomizer.

import org.apache.catalina.connector.Connector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {

    private static final Logger log = LoggerFactory.getLogger(GracefulShutdown.class);

    private volatile Connector connector;

    @Override
    public void customize(Connector connector) {
        this.connector = connector;
    }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        this.connector.pause();
        Executor executor = this.connector.getProtocolHandler().getExecutor();
        if (executor instanceof ThreadPoolExecutor) {
            try {
                ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                threadPoolExecutor.shutdown();
                if (!threadPoolExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                    log.warn("Tomcat thread pool did not shut down gracefully within "
                            + "30 seconds. Proceeding with forceful shutdown");
                }
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
    }
}


In the implementation shown above, the ThreadPoolExecutor will be waiting 30 seconds prior to proceeding with the shutdown. Pretty simple, right? With that in place, it’s now time to register this bean to the application context and inject it to Tomcat.

To do that, just create the following Spring @Beans.

@Bean
public GracefulShutdown gracefulShutdown() {
    return new GracefulShutdown();
}

@Bean
public ConfigurableServletWebServerFactory webServerFactory(final GracefulShutdown gracefulShutdown) {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addConnectorCustomizers(gracefulShutdown);
    return factory;
}


How to Test?

To test this implementation, I just created a LongProcessController that which has a Thread.sleep of 10 seconds.

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LongProcessController {

    @RequestMapping("/long-process")
    public String pause() throws InterruptedException {
        Thread.sleep(10000);
        return "Process finished";
    }
}


Now, it’s just a matter of running your Spring Boot application, making a request to the /long-process endpoint, and, in the meantime, kill it with a SIGTERM.

Locate the Process ID

When you start the application, you can locate the process ID in the logs. In my case, it’s 6578.

2018-06-28 20:37:28.292  INFO 6578 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-06-28 20:37:28.296  INFO 6578 --- [           main] c.m.wd.gracefulshutdown.Application      : Started Application in 2.158 seconds (JVM running for 2.591)


Request and Shutdown

Perform a request with the /long-process endpoint. I’m using curlfor that:

$ curl -i localhost:8080/long-process


Send a SIGTERM to the process:

$ kill 6578


The curl request still needs to respond as below:

HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 14
Date: Thu, 28 Jun 2018 18:39:56 GMT

Process finished


Summary

Congratulations! You just learned how to gracefully shutdown Spring Boot apps.

Spring Framework Spring Boot application

Published at DZone with permission of Marcos Barbero, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)
  • Java, Spring Boot, and MongoDB: Performance Analysis and Improvements
  • Spring Boot Secured By Let's Encrypt
  • How To Build Web Service Using Spring Boot 2.x

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: