我正在处理我的Java Server应用程序请求服务器重新启动时运行的bash脚本。该脚本确实需要在Java应用程序的进程树之外操作。
我使用ProcessBuilder以以下方式调用Java中的重新启动脚本:
// Vars declared at the top of the file
private static final String LOC = "/some/directory/";
private static final String RESTART_SCRIPT = LOC + "restart.sh";
...
// In the function that is invoked to handle reboot behavior
final ProcessBuilder pb = new ProcessBuilder(RESTART_SCRIPT);
Process p = pb.start();
此脚本执行以下操作,以删除另一个处理所有重启逻辑的脚本。看起来如下:
#!/bin/bash
(bash /some/directory/shutdownHandler.sh "true" &)
exit 0
在Java应用程序中,我调用包含ProcessBuilder Logic的函数时,我看不到shutdownhandler.sh脚本中逻辑的效果。即使是简单的文本回声,也没有发生在文件中。我已经检查了我有正确的权限。
直接从命令行执行restart.sh时,它可以按预期工作。
请建议我为什么看到这种行为差异。Java是否有某种方式杀死了守护程序?
我建议您尝试以下简化:
final String[] RESTART_COMMAND = { "nohup", "/some/directory/shutdownHandler.sh", "true" };
final ProcessBuilder pb = new ProcessBuilder(RESTART_COMMAND);
Process p = pb.start();
//DON'T waitFor()
使用nohup
并避免使用waitFor
应该具有相同的效果您的RESTART_SCRIPT
工具:这两个过程'生命周期都是独立的(jvm
不等待shutdownHandler.sh
,Java进程的终止不会导致shutdownHandler.sh
的中断)。
我找到了一种使脚本shutdownHandler.sh
在我描述的用法方案中正确触发的方法。问题在于我如何使shutdownHandler.sh
进行危险。我已将restart.sh
更改为:
#!/bin/bash
LOGFILE="/some/log/directory/scriptLog.log"
(setsid /some/directory/shutdownHandler.sh "true" >$LOGFILE 2>&1 < /dev/null &)
exit 0
上面有一些关键的事情:
- 处理脚本的
stdout
,stderr
和stdin
。stdout
和stderr
被定向到LOGFILE
中,并将dev/null
连接到stdin
- 与控制tty断开连接
- 启动的修改脚本。
shutdownHandler.sh
不会与JVM
处于同一过程树中