subprocess执行java命令残留进程解决

问题简述

需求是通过Python执行命令java -java springboot-demo.jar

于是,我使用subprocess.Popen()来启停。但是我发现在关闭子进程后,java进程并没有正确关闭。

这是由于上面的方法实际原理是另外开启一个cmd命令来运行java -jar命令,后面用popen.terminate()也只能关闭cmd的命令,cmd命令被kill掉后,java进程由系统来托管,从而导致java进程并没有正确关闭。

Bug复现

执行代码:

import subprocess

if __name__ == '__main__':
# 执行java -jar
t = subprocess.Popen(["java", "-jar", "springboot-demo.jar"])
# Popen是异步的,所以需要等待几秒,再关闭
time.sleep(10)
# 关闭子进程
t.terminate()
# 等待关闭结束
t.wait()

发现残留的java进程

image

解决

思路

我的解决思路是,稍微修改java代码,在执行java -jar命令后,将java进程id(pid)暴露出来。

当需要关闭程序时,读取暴露出来的java进程id,使用kill命令,将进程杀死。

详述

首先修改java代码,我使用的代码框架是springboot,所以在springboot的启动类上修改如下:

@SpringBootApplication
public class SpringbootDemoApplication {

public static void main(String[] args) {
SpringApplication application = new SpringApplication(SpringbootDemoApplication.class);
// 获取jar包执行的路径
ApplicationHome h = new ApplicationHome(SpringbootDemoApplication.class);
File source = h.getSource();
System.out.println("<<<<<< jar 执行目录:" + source.getParentFile().toString() + " >>>>>>");
String app_pid_file = source.getParentFile().toString() + "\\app.pid";
application.addListeners(new ApplicationPidFileWriter(app_pid_file)); // 把进程号放到这个文件中
application.run();

}

}

其中,

  • source.getParentFile().toString()可以获得jar包所在的目录。
  • application.addListeners(new ApplicationPidFileWriter(app_pid_file));将在jar包同级目录下生成app.pid的文件,该文件中写入了springboot运行的进程号

然后修改Python代码

import subprocess

if __name__ == '__main__':
JAR_DIR = 'XXX' # jar包所在目录
# 执行java -jar
t = subprocess.Popen(["java", "-jar", os.path.join(f"{JAR_DIR}", "springboot-demo.jar"])
# Popen是异步的,所以需要等待几秒,再关闭
time.sleep(10)
# 关闭子进程
t.terminate()
# 等待关闭结束
t.wait()
# 关闭java进程
app_pid_file_path = os.path.join(JAR_DIR, "app.pid")
if os.path.exists(app_pid_file_path):
with open(app_pid_file_path, 'r') as f:
pid = f.read()
print(f"正在关闭java 进程, pid: {int(pid)}")
# 在windows系统下执行杀死进程的命令,其他系统可能命令不同
subprocess.run(["cmd", "/c", "taskkill", "/pid", f'{int(pid)}', "-f"])
os.remove(app_pid_file_path) # 删除app.pid文件

总结

Refs

  1. subprocess.Popen执行程序以及关闭进程
文章作者: Met Guo
文章链接: https://guoyujian.github.io/2023/12/07/subprocess%E6%89%A7%E8%A1%8Cjava%E5%91%BD%E4%BB%A4%E6%AE%8B%E7%95%99%E8%BF%9B%E7%A8%8B%E8%A7%A3%E5%86%B3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Gmet's Blog