一. 业务需求
SFTP上有多个目录, 每小时要下载一次文件, 每个目录的下载任务都是一个独立的工作流任务.
二.问题描述
手动执行每个任务可以正常执行, 但是当所有任务都开启定定时任务执行时(每小时执行一次),任务实例就会报错.
三.问题分析
-
查看服务端和worker端的日志, 并没有报错(此处有坑, 不报错并不代表没问题).
-
查看官方文档, 怀疑是多个任务并发的导致的.
-
分析服务端源码.(太TM费劲了😨, 最后再考虑)
-
在本地开发环境模拟多个任务同时执行.
问题虽然复现了, 但是依然没有报错. 难道真的要读服务端源码吗? 人家也没报错呀, 开始抓狂了.一天的时间就是这样反复测试中度过了😒~
四.问题解决
程序员可能只有夜深人静的时候才会有灵感.(●’◡’●)
来吧, 把多个任务的cron修改为每10秒执行一次, 来个暴力测试🤬.
监控两端的日志, 突然看到worker端一部分日志似乎有问题.
看到了吗?不同的目录,ftp的连接信息竟然打印两次.
好像突然明白了什么, 难道是代码中打印了两行日志吗?我希望不是,因为此时我已经意识到问题原因了😮.
代码中只有一条打印信息,为什么会打印两条呐?大牛一看就明白了, 呵呵, 好像在夸自己😂.
这说明同一时刻有两个线程在执行这个方法, 而这个方法正好是连接SFTP的方法.
好吧,那就把方法设置为同步, 该 synchronized
出场了.
/**
* 下载文件
* @return 二进制流
*/
public synchronized byte[] downloadFile(String filePath) {
log.info("sftp下载文件 filePath{} 开始", filePath);
connect();
try (InputStream inputStream = sftp.get(filePath);) {
//进入FTP服务器文件目录
log.info("DownloadFile:{},success from sftp", filePath);
log.info("ftp下载文件结束");
// inputStream.readAllBytes(); jdk9
return IOUtils.toByteArray(inputStream);
} catch (SftpException | IOException e) {
log.error("sftp下载文件失败");
throw new FileSyncException("ftp下载文件失败");
} finally {
disconnect();
}
}
五.重启测试
终于可以去看世界杯了(2022卡塔尔世界杯:德国VS日本).
看看日耳曼如何虐小RB.
六.总结
- 日志非常重要, 代码中一定要详细记录日志.
- 要养成仔细看日志的习惯.不报错并不代表没问题.