美文网首页
SpringBoot 优雅退出

SpringBoot 优雅退出

作者: Chaos_John | 来源:发表于2020-12-09 00:18 被阅读0次

欢迎转载,但请在开头或结尾注明原文出处【blog.chaosjohn.com】

背景

公司某项目的后端技术栈采用的是 SpringBoot + Kotlin,具体细节本文不作展开。

业务中,用户在我们平台上购买产品,我们通过实时请求供应商的交易API,在商户余额(即我们在供应商那边的储值)里扣除对应的金额后,才会将产品的“源文件”返回,进而交付给用户。

项目迭代中我们需要不断的部署新的版本上线,最初的做法很暴力,构建新的 flatjar 运行起来,然后直接结束掉 旧的 java 进程

然后就发现问题了:某次购买行为中,交易API的请求发送出去了,还没等待请求返回,进程就被杀死了,造成储值余额被扣了,但是“源文件”并没有拿到,而供应商的API又存在延迟,即交易API处理成功,但是通过订单查询API却查不到。

所以,如何才能在 java 进程被杀死的时候,做完 善后工作 再退出呢?

解决

一般我们杀死进程,都是给进程发送信号 Signal

  • SIGINT
  • SIGTERM

这里我们用到两个类:

  • sun.misc.Signal,代表信号
  • sun.misc.SignalHandler,用来处理进程接收到的信号

同时,我们设计以下全局变量:

  • var killSignalReceived = false // 用来表示是否接收到终止信号
  • val jobSet = mutableSetOf<String>() // 表示需要在结束之前等待完成的任务

所以交易API的请求处理,我们将改成:

if (!killSignalReceived) { // 只有为 `false`,才进行交易处理
  synchronized(jobSet) {
      jobSet.add(jobTitle) // 处理之前,将当前处理任务存入 `jobSet`
  }
  // Todo: 具体实现请求交易API的处理
  synchronized(jobSet) {
      jobSet.remove(jobTitle) // 处理结束,将当前处理任务从 `jobSet` 中移除
  }
}

在程序主函数中,新增:

val killHandler = SignalHandler {
    logger.error("intercept signal of ${it.toJson()}")
    killSignalReceived = true
    while (jobSet.isNotEmpty()) {
        logger.error("Background Jobs: \n\t\t" + jobSet.joinToString("\n\t\t") + "\n")
        Thread.sleep(1000)
    }
    exitProcess(0)
}
Signal.handle(Signal("INT"), killHandler)
Signal.handle(Signal("TERM"), killHandler)

当 java 进程接收到 SIGINTSIGTERM 信号后:

  • killSignalReceived 置为 true
  • 循环检查 jobSet 是否为空
    • 不为空,打印当前未结束的任务列表,等待1s后再次检查
    • 为空,程序退出

如果需要忽略 善后工作 强行退出,给进程发送 SIGKILL 即可:

  • kill -KILL pid
  • kill -9 pid

相关文章

  • SpringBoot 优雅退出

    欢迎转载,但请在开头或结尾注明原文出处【blog.chaosjohn.com】[https://blog.chao...

  • docker 优雅退出

    本文主要阐述如何让 docker 容器优雅的终止。 优雅退出定义 所谓优雅退出,指的是程序在退出之前,有清理资源、...

  • JVM优雅退出

    背景 在某个Java应用增加新功能,缩容机器,或者应用以及机器发生异常,通常会停止正在运行的应用,该应用通常正在运...

  • Nodejs 优雅退出

    前言 我们在Nodejs业务逻辑复杂的时候,很难做到完全没有内存泄漏,和出现uncaughtException的异...

  • Java 优雅退出

    前言 先思考几个问题 Java 服务为什么会挂掉? 什么情况 Java 进程会挂掉? Java 进程挂掉如何做优雅...

  • 如何优雅的退出 App ?这样优雅的退出 App !

    只需要下面这行代码(肯定还有其他的代码),当然,这是有限制的(。﹏。),而且只是退出当前的 task 而已! Ba...

  • SpringBoot优雅整合Mybatis

    SpringBoot优雅整合Mybatis - 作业部落 Cmd Markdown 编辑阅读器

  • go程

    golang里捕获进程信号实现优雅退出的方法 一、定时与 同步退出 二、锁 互斥锁Mutex Lock,UnLock

  • Go并发模型:并发协程chan的优雅退出

    Go并发模型:并发协程chan的优雅退出 go chan的使用

  • Java程序优雅停机v2

    springboot 2.3新增了优雅停机策略见:https://www.jianshu.com/p/835849...

网友评论

      本文标题:SpringBoot 优雅退出

      本文链接:https://www.haomeiwen.com/subject/ylecgktx.html