背景
最近來了個實習僧小弟,安排他實作對目标網站 連通性檢測的小功能,簡單講就是将下邊的shell 腳本換成Java 代碼來實作
#!/bin/bash
URL="https://www.baidu"
HTTP_CODE=`curl -o /dev/null -s -w "%{http_code}" "${URL}"`
#echo $HTTP_CODE
if [ $HTTP_CODE != '200' ];then
curl 'https://oapi.dingtalk.com/robot/send?access_token=xx' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
"text": {
"content": "百度平台狀态不正常,請注意!"
},
"isAtAll": true
}'
fi
功能實作
使用spring task
@Scheduled(cron = "0 0 0/1 * * ? ")
public void startSchedule() {
log.info("開始執行定時任務 ,檢測百度網站連通性");
try {
HttpResponse response = HttpRequest.get("").execute();
if (HttpStatus.HTTP_OK != response.getStatus()) {
this.send2DingTalk(response.getStatus());
}
log.info("請求百度成功,傳回封包:{}",response.body());
} catch (HttpException e) {
log.error("請求異常百度:{}", e);
this.send2DingTalk(e.getMessage());
}
log.info("執行檢測百度網站連通任務完畢");
}
問題描述
部署在伺服器上,我的老jio本 都已經呼叫任務狀态不正常了,可是小弟的Java 代碼還是沒有執行通知
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicWZwpmL09Gaz5WZlJ3YT9VQLZzd6V1X0MjMzcTMwMzNwkTMwIzLc12bj5CZ19GbjRzZpBnLzN3bvw1LcpDc0RHaiojIsJye.jpeg)
- 去翻生産日志,隻輸入了開始并沒有輸出定時任務結束,感覺是哪裡卡死,想當然以為如果逾時總會到catch 邏輯,排查無果
- 由于任務是一小時一次,如何快速觸發一下這個異常,還原事故現場
- 由于使用簡單的Spring Task 沒有圖形化界面和API接口
Arthas 還原事故現場,重新觸發任務
核心拿到 spring context 然後執行它的
startSchedule
方法
确定監控點
- SpringMVC 的請求會通過
執行RequestMappingHandlerAdapter
到達目标接口上進行處理invokeHandlerMethod
- 而在
類中有 getApplicationContext()RequestMappingHandlerAdapter
@Nullable
public final ApplicationContext getApplicationContext() throws IllegalStateException {
if (this.applicationContext == null && this.isContextRequired()) {
throw new IllegalStateException("ApplicationObjectSupport instance [" + this + "] does not run in an ApplicationContext");
} else {
return this.applicationContext;
}
}
- 任意執行一次請求擷取到
target 目标,然後執行RequestMappingHandlerAdapter
getApplicationContext
tt指令 擷取到ApplicationContext
- arthas 執行 tt
tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
- 任意執行一次web 請求,tt 即可捕獲
Arthas 手動觸發生産定時任務的危險操作 - 根據目标的索引,執行自定義 OGNL 表達式即可
tt -i 1019 -w 'target.getApplicationContext()'
使用ApplicationContext擷取 定時任務bean 執行 startSchedule
tt -i 1000 -w 'target.getApplicationContext().getBean("baiduSchedule").startSchedule()'
ok 任務重新觸發了
事故原因調查清楚,由于使用hutool 的工具類 沒有設定timeout 導緻無限等待,是以沒有執行catch 邏輯
總結
- 以上吓哭實習僧的操作
生産操作,隻是提供個思路 ,當然可以衍生其他業務場景的操作禁止
- 核心是通過Arthas 來抓取Spring ApplicationContext 對象,然後擷取bean 進行執行方法
- 關于Arthas 是Alibaba開源的Java診斷工具,深受開發者喜愛
- 歡迎關注我們獲得更多的好玩JavaEE 實踐
Arthas 手動觸發生産定時任務的危險操作