共计 2323 个字符,预计需要花费 6 分钟才能阅读完成。
背景
最近来了个实习僧小弟,安排他实现对目标网站 连通性检测的小功能, 简单讲就是将下边的 shell 脚本换成 Java 代码来实现
1#!/bin/bash
2URL="https://www.baidu"
3HTTP_CODE=`curl -o /dev/null -s -w "%{http_code}" "${URL}"`
4#echo $HTTP_CODE
5if [$HTTP_CODE != '200'];then
6curl 'https://oapi.dingtalk.com/robot/send?access_token=xx' \
7 -H 'Content-Type: application/json' \
8 -d '{"msgtype":"text",
9 "text": {
10 "content": "百度平台状态不正常,请注意!"
11 },
12 "isAtAll": true
13 }'
14
15fi
功能实现
使用 spring task
1@Scheduled(cron = "0 0 0/1 * * ?")
2public void startSchedule() {3 log.info("开始执行定时任务,检测百度网站连通性");
4 try {5 HttpResponse response = HttpRequest.get("").execute();
6 if (HttpStatus.HTTP_OK != response.getStatus()) {7 this.send2DingTalk(response.getStatus());
8 }
9 log.info("请求百度成功,返回报文:{}",response.body());
10 } catch (HttpException e) {11 log.error("请求异常百度:{}", e);
12 this.send2DingTalk(e.getMessage());
13 }
14 log.info("执行检测百度网站连通任务完毕");
15}
问题描述
部署在服务器上,我的老 jio 本 都已经呼叫任务状态不正常了, 可是小弟的 Java 代码还是没有执行通知
- 去翻生产日志,只输入了开始并没有输出定时任务结束,感觉是哪里卡死,想当然以为如果超时总会到 catch 逻辑,排查无果
- 由于任务是一小时一次,如何快速触发一下这个异常,还原事故现场
- 由于使用简单的 Spring Task 没有图形化界面和 API 接口
Arthas 还原事故现场,重新触发任务
核心拿到 spring context 然后执行它的 startSchedule
方法
确定监控点
- SpringMVC 的请求会通过
RequestMappingHandlerAdapter
执行invokeHandlerMethod
到达目标接口上进行处理 - 而在
RequestMappingHandlerAdapter
类中有 getApplicationContext()
1@Nullable
2public final ApplicationContext getApplicationContext() throws IllegalStateException {3 if (this.applicationContext == null && this.isContextRequired()) {4 throw new IllegalStateException("ApplicationObjectSupport instance [" + this + "] does not run in an ApplicationContext");
5 } else {
6 return this.applicationContext;
7 }
8}
- 任意执行一次请求获取到
RequestMappingHandlerAdapter
target 目标,然后执行getApplicationContext
tt 命令 获取到 ApplicationContext
- arthas 执行 tt
1tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
- 任意执行一次 web 请求,tt 即可捕获
- 根据目标的索引,执行自定义 OGNL 表达式即可
1tt -i 1019 -w 'target.getApplicationContext()'
使用 ApplicationContext 获取 定时任务 bean 执行 startSchedule
1tt -i 1000 -w 'target.getApplicationContext().getBean("baiduSchedule").startSchedule()'
ok 任务重新触发了
事故原因调查清楚,由于使用 hutool 的工具类 没有设置 timeout 导致无限等待,所以没有执行 catch 逻辑
总结
以上吓哭实习僧的操作 禁止
生产操作,只是提供个思路,当然可以衍生其他业务场景的操作
核心是通过 Arthas 来抓取 Spring ApplicationContext 对象,然后获取 bean 进行执行方法
关于 Arthas 是 Alibaba 开源的 Java 诊断工具,深受开发者喜爱
欢迎关注我们获得更多的好玩 JavaEE 实践
推荐阅读:
《深入理解 Java 内存模型》读书笔记
面试 - 基础篇
Spring Boot 2.0 迁移指南
SpringBoot 使用 Docker 快速部署项目
为什么选择 Spring 作为 Java 框架?
SpringBoot RocketMQ 整合使用和监控
Spring Boot 面试的十个问题
使用 Spring Framework 时常犯的十大错误
SpringBoot Kafka 整合使用
SpringBoot RabbitMQ 整合使用
上篇好文:
如何优雅关闭 Spring Boot 应用
正文完
发表至: java
2019-08-07