• 实现优雅地关闭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等。这里就不整活了铁汁们,今天就到这里,拜拜。

  • 相关阅读:
    括号序列
    乘积最大
    装箱问题
    开心的金明
    金明的预算方案(有依赖的背包问题)
    砝码称重
    (枚举)算法竞赛入门经典(7.1.2)最大乘积
    (枚举)算法竞赛入门经典(7.1.1)除法
    Zabbix历史数据清理
    sonarqube6.7.1使用
  • 原文地址:https://www.cnblogs.com/huyufan/p/13294343.html
Copyright © 2020-2023  润新知