需要实现看门狗功能,定时检测另外一个程序是否在运行,使用 crontab 仅可以实现检测程序是否正在运行,无法做到扩展,如:手动重启、程序升级(如果只需要实现自动升级功能可以使用 inotify)等功能;最后决定使用 Spring Boot 调用 Shell 脚本来实现

一、脚本

1.1 启动脚本

#!/bin/bash

ps -ef | grep "demo-app-0.0.1-SNAPSHOT.jar" | grep -v "grep"

if [ "$?" -eq 0 ]
then # sleep
echo $(date "+%Y-%m-%d %H:%M:%S") "process already started!" else nohup java -jar -server /project/watchdog/demo-app-0.0.1-SNAPSHOT.jar &
echo $(date "+%Y-%m-%d %H:%M:%S") "process has been started!" fi

1.2 重启脚本

#!/bin/bash

pid=`ps -ef | grep "demo-app-0.0.1-SNAPSHOT.jar" | grep -v "grep" | awk '{print $2}'`

for id in $pid
do
kill -9 $id
echo "killed $id"
done nohup java -jar -server /project/watchdog/demo-app-0.0.1-SNAPSHOT.jar &
echo $(date "+%Y-%m-%d %H:%M:%S") "process has been restarted!"

二、功能实现

将脚本放置在程序的资源目录下,每次程序启动时将脚本读取到指定位置,然后再通过定时任务执行脚本

配置内容:

shell:
directory: /project/watchdog
startupFileName: startup.sh
restartFileName: restart.sh
@Configuration
@ConfigurationProperties(prefix = "shell")
public class ShellProperties { private String directory;
private String startupFileName;
private String restartFileName; /* getter & setter */ public String getFullName(String fileName) {
return directory + File.separator + fileName;
}
}

2.1 启动时将脚本读取到指定位置

@Component
public class InitRunner implements CommandLineRunner { @Autowired
private ShellProperties shellProperties; @Autowired
ResourceLoader resourceLoader; @Override
public void run(String... args) throws Exception {
generateFile(shellProperties.getStartupFileName());
generateFile(shellProperties.getRestartFileName());
} private void generateFile(String fileName) throws IOException { String fileFullName = shellProperties.getFullName(fileName);
File file = new File(fileFullName);
if(file.exists()) {
return;
} // 如果文件已存在,FileWriter 会先删除再新建
FileWriter fileWriter = new FileWriter(fileFullName); Resource resource = resourceLoader.getResource("classpath:" + fileName);
InputStream inputStream = resource.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String data;
while ((data = bufferedReader.readLine()) != null) {
fileWriter.write(data + "\n");
} bufferedReader.close();
inputStreamReader.close();
inputStream.close(); fileWriter.close(); // 设置权限,否则会报 Permission denied
file.setReadable(true);
file.setWritable(true);
file.setExecutable(true);
}
}

2.2 定时任务定时任务执行脚本

@Component
public class ShellTask { private static final Logger logger = LoggerFactory.getLogger(ShellTask.class); @Autowired
private ShellProperties shellProperties; @Scheduled(cron = "0/10 * * * * ? ")
public void start() throws IOException {
executeShell(shellProperties.getStartupFileName());
} private void executeShell(String fileName) throws IOException { String fileFullName = shellProperties.getFullName(fileName);
File file = new File(fileFullName);
if(!file.exists()) {
logger.error("file {} not existed!", fileFullName);
return;
} ProcessBuilder processBuilder = new ProcessBuilder(fileFullName);
processBuilder.directory(new File(shellProperties.getDirectory())); Process process = processBuilder.start(); // String input;
// BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
// BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
// while ((input = stdInput.readLine()) != null) {
// logger.info(input);
// }
// while ((input = stdError.readLine()) != null) {
// logger.error(input);
// } int runningStatus = 0;
try {
runningStatus = process.waitFor();
} catch (InterruptedException e) {
logger.error("shell", e);
} if(runningStatus != 0) {
logger.error("failed.");
}else {
logger.info("success.");
}
}
}

2.3 扩展

  1. 本例只实现了定时检测程序是否运行,如果没有运行则启动程序;如有需要可以添加接口,调用接口重启程序;或者添加定时任务定时检测程序是否有更新,如果有更新则下载新的 jar 包然后重启程序
  2. 看门狗程序自己可以使用 crontab 定时检测是否正在运行,模仿上面的启动脚本编写看门狗的启动脚本,然后添加定时任务:
crontab -e
*/10 * * * * /project/watchdog/watchdog.sh
sudo systemctl reload crond.service

完整代码:GitHub

参考:java去调用并执行shell脚本以及问题总结

最新文章

  1. .NetCore之EF跳过的坑
  2. bzoj 3531 旅行
  3. Using Amazon API Gateway with microservices deployed on Amazon ECS
  4. sqlserver 查询库中有多少张表
  5. 在非MFC的win 32程序里面能够使用CString类
  6. kylin客户端(python编写)不能按照预期的segment进行rebuild
  7. Matlab绘图基础——一些标准三维曲面
  8. 基础补充:使用xlrd模块读取excel文件
  9. H5取经之路——HTML的基本标签
  10. 洛谷P4063 [JXOI2017]数列(dp)
  11. 【转】SEGGER Embedded Studio 新建stm32f103工程
  12. Mysql常用函数总结(二)
  13. BZOJ.4293.[PA2015]Siano(线段树)
  14. spring boot 微服务例子一
  15. linux 命令大全,我去
  16. 解决“ 故障模块名称: clr.dll ”
  17. const与预处理宏#define的区别
  18. python中的内置函数总结
  19. SpriteKit在复制节点时留了一个巨坑给开发者,需要开发者手动把复制节点的isPaused设置为false
  20. iOS 给三方日历加上农历

热门文章

  1. 小白如何学习PyTorch】25 Keras的API详解(下)缓存激活,内存输出,并发解决
  2. 左值 lvalue,右值 rvalue 和 移动语义 std::move
  3. 对udp dns的思考2
  4. tcp输入数据 慢速路径处理 && oob数据 接收 && 数据接收 tcp_data_queue
  5. 使用GitHub API上传文件及GitHub做图床
  6. 线程范围内的环境变量---ThreadLocal
  7. Kubernetes笔记(六):了解控制器 —— Deployment
  8. c++11-17 模板核心知识(五)—— 理解模板参数推导规则
  9. Nacos一致性算法
  10. K尾相等数(模运算)