實現優雅地關閉Docker中的java服務


  時至今日,Docker在項目中的應用越來越普遍了,但往往會遭遇一些麻煩,比如說,有幾個請求至Docker中的服務,發起了事務處理業務,但每個事務完成可能需要1-5分鍾,而此時我們正要將Docker停機准備發布新版本,那如何在不影響當前業務執行的停止服務呢?有人會說,用docker stop,默認10秒延遲關停,加個延時參數-t 300,完美!有一說一,確實,但問題又來了,當前服務中的業務處理滿足了,如何防止新的請求產生?所以,如何優雅地停機成了開發者關注的問題。好了,不多BB,直接開整鐵汁們。

  思路:執行docker stop -t 360,Java服務會收到容器發出的SIGTERM信號,監聽到此信號並執行相關操作,如注銷MQ或Eureka,關閉Controller或ThreadPool等。

  先貼一段代碼,關於如何監聽SIGTERM,並關閉RabbitMQ。

public class XXXApplication {

    ************
  private static boolean stopHandle = false;
public static void main(String[] args) {

        SpringApplication springApplication = new SpringApplication(XXXApplication.class);

        ************

        ApplicationContext context = springApplication.run(args);

        ApplicationParam appParam = context.getBean(ApplicationParam.class);
      // 監聽信號 handleSignal(
"TERM", context);
     ************
} 

private static void handleSignal(String name, ApplicationContext context) {
   Signal signal = new Signal(name);
signal.handle(signal,Signal -> {
logger.info("signal received: "+ signal.getName());
if("TERM".equals(signal.getName())){
shutdown(context);
stopHandleApi = true;
}
});
}

private static void shutdown(ApplicationContext context) {
// 關閉rabbit mq
logger.info("shutdown rabbitMQ listener! ");
RabbitListenerEndpointRegistry rer = context.getBean(RabbitListenerEndpointRegistry.class);
rer.stop();
}
}
 

  這里將stopHandle這個靜態常量設為true的目的是表明程序即將停止,這樣也能在其它地方應用,比如,寫一個攔截器,當接收到新的請求時攔截,判斷stopHandle是否為true,如果是則說明服務要停止了,不再接受新請求,同時返回404給客戶端。

  

public class RestApiInterceptor  extends HandlerInterceptorAdapter {
    private static final Logger logger = LogManager.getLogger(RestApiInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        logger.info("isStopHandleApi = "+ FintechEkycApplication.isStopHandleApi());
        if(ShortenLinkSysApplication.isStopHandleApi()){
            response.setStatus(404);
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().println("application is stopping! Please wait minutes and request after it restart !");
            return false;
        }else {
            return true;
        }
    }

  測試效果如圖:

  總結:如果希望代碼更優雅一點可以利用事件驅動,寫個繼承TomcatConnectorCustomizer的類來處理像Thread Pool、Web servlet等。這里就不整活了鐵汁們,今天就到這里,拜拜。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM