Preface
Often the pronoun for "stop service" is violence, regardless of the consequences, because when a forced stop occurs, it doesn't matter if there are any running threads in it.
It happens that recently, because of the auto scalinng in AWS, unknown friends can interpret it as AWS can automatically expand or shrink our servers, which can reduce costs and allow self-google to get a better understanding.
This is a good starting point, but I also found a problem when I actually used it: if the docker was stopped, the one that might be alive inside would be forced to stop. What should I do at this time?
text
according to
- The docker stop command actually executes the kill pid command, and SIGNTEMR is used by default if the stop signal is not followed
- And if the main process in the docker is stopped, the docker will naturally stop.
So the key to inferring is that we need to manipulate spring boot with elegant stop, our protagonist today.
So much rubbish has to be mentioned and the following topics have to be addressed. There are actually many online tutorials in this area, such as the one below, which is well written:
https://www.cnblogs.com/harrychinese/p/SpringBoot-graceful-shutdown.html
However, almost all online documents place injection bean s in the startup class, and I place them in the @configuration class. Here's the main code:
First is the code that the primary listening container closes and handles:
package com.demo.timeout.tomcat; import org.apache.catalina.connector.Connector; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import org.springframework.stereotype.Component; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @Component public class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> { private volatile Connector connector; private int waitTime; @Value("${STOP_WAIT_TIMEOUT}") public void setWaitTime(int waitTime) { this.waitTime = waitTime; } @Override public void customize(Connector connector) { this.connector = connector; } @Override public void onApplicationEvent(ContextClosedEvent contextClosedEvent) { this.connector.pause(); Executor executor = this.connector.getProtocolHandler().getExecutor(); try { if (executor instanceof ThreadPoolExecutor) { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; threadPoolExecutor.shutdown(); if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) { System.out.println("Tomcat Process in" + waitTime + " Can't end in seconds, try to force end"); } } } catch (Exception e) { e.printStackTrace(); Thread.currentThread().interrupt(); } } }
Then inject the code into it:
package com.demo.timeout.config; import com.demo.timeout.tomcat.GracefulShutdown; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class GracefulShutDownConfig { @Autowired private GracefulShutdown gracefulShutdown; @Bean public ServletWebServerFactory servletContainer() { TomcatServletWebServerFactory tomcatServletWebServerFactory = new TomcatServletWebServerFactory(); tomcatServletWebServerFactory.addConnectorCustomizers(gracefulShutdown); return tomcatServletWebServerFactory; } }
Finally, I wrote a test code for the API
package com.demo.timeout.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/30s-process") public String longProcessAPI(){ System.out.println("enter this long process function"); try { Thread.sleep(30000); } catch (InterruptedException e) { e.printStackTrace(); } return "30s Thread Start"; } }
If you need to see the code I uploaded: