7.8 KiB
7.8 KiB
完成图片保存重试机制
🔄 重试策略
为了确保4张完成图片都能成功保存,系统实现了双层重试机制。
📊 重试架构
第一层:网络层重试(ScriptClient)
位置: ScriptClient.getImagePng()
.timeout(Duration.ofSeconds(10)) // 10秒超时
.retry(3) // 网络失败重试3次(立即重试)
重试条件:
- 网络连接失败
- HTTP错误
- 超时(10秒)
重试间隔: 立即重试(无延迟)
第二层:业务层重试(CompletionImageService)
位置: CompletionImageService.downloadAndSaveImage()
.retryWhen(Retry.fixedDelay(3, Duration.ofMillis(500))
.doBeforeRetry(retrySignal -> {
long attempt = retrySignal.totalRetries() + 1;
log.warn("下载图片失败,开始第{}次重试: codeNo={}, imageName={}",
attempt, codeNo, imageName);
})
)
重试条件:
- 图片下载失败
- 文件写入失败
- 任何异常
重试间隔: 500毫秒固定延迟
重试次数: 3次
🎯 完整重试流程
graph TD
A[开始下载图片] --> B[ScriptClient.getImagePng]
B --> C{成功?}
C -->|失败| D{第一层重试<3次?}
D -->|是| B
D -->|否| E[第一层失败]
C -->|成功| F[保存到文件系统]
E --> G{第二层重试<3次?}
F --> H{保存成功?}
H -->|失败| G
G -->|是| I[等待500ms]
I --> B
G -->|否| J[最终失败]
H -->|成功| K[保存成功]
📝 日志示例
成功场景(无重试)
DEBUG - 开始下载图片: codeNo=MYNM5JHA, imageName=首次主页.png, scriptPath=/rr3/首次主页.png
DEBUG - 获取图片成功: path=/rr3/首次主页.png, 数据大小=245678字节
DEBUG - 图片保存成功: codeNo=MYNM5JHA, imageName=首次主页.png, size=245678字节, path=20251103/MYNM5JHA/homepage.png
重试场景(网络抖动)
DEBUG - 开始下载图片: codeNo=MYNM5JHA, imageName=首次赏金.png, scriptPath=/rr3/首次赏金.png
WARN - 获取图片失败: path=/rr3/首次赏金.png, error=Connection timeout
WARN - 下载图片失败,开始第1次重试: codeNo=MYNM5JHA, imageName=首次赏金.png
DEBUG - 获取图片成功: path=/rr3/首次赏金.png, 数据大小=189234字节
DEBUG - 图片保存成功: codeNo=MYNM5JHA, imageName=首次赏金.png, size=189234字节
最终失败场景
DEBUG - 开始下载图片: codeNo=MYNM5JHA, imageName=结束赏金.png, scriptPath=/rr3/结束赏金.png
WARN - 获取图片失败: path=/rr3/结束赏金.png, error=404 Not Found
WARN - 下载图片失败,开始第1次重试: codeNo=MYNM5JHA, imageName=结束赏金.png
WARN - 获取图片失败: path=/rr3/结束赏金.png, error=404 Not Found
WARN - 下载图片失败,开始第2次重试: codeNo=MYNM5JHA, imageName=结束赏金.png
WARN - 获取图片失败: path=/rr3/结束赏金.png, error=404 Not Found
WARN - 下载图片失败,开始第3次重试: codeNo=MYNM5JHA, imageName=结束赏金.png
WARN - 获取图片失败: path=/rr3/结束赏金.png, error=404 Not Found
ERROR - 下载图片失败,已重试3次: codeNo=MYNM5JHA, imageName=结束赏金.png, 最后错误=404 Not Found
WARN - 图片下载和保存最终失败: codeNo=MYNM5JHA, imageName=结束赏金.png, error=404 Not Found
INFO - 完成图片保存成功: codeNo=MYNM5JHA, 成功数量=3/4
📊 重试统计
单张图片最多重试次数
总重试次数 = 第一层重试 × 第二层重试
- 第一层(网络层):3次立即重试
- 第二层(业务层):3次延迟重试(每次500ms)
- 理论最大尝试:1 + 3 + 3 = 7次
- 实际有效重试:约 3-6次(取决于失败类型)
超时时间
单次尝试总超时:
- 网络超时:10秒
- 网络重试:10s × 3 = 30秒
- 单次最长时间:约40秒
整体超时:
- 业务层重试间隔:500ms × 3 = 1.5秒
- 最长总时间:约120秒(极端情况)
🎯 容错处理
部分图片失败不影响整体
即使某张图片下载失败,其他图片依然会保存成功:
{
"saveTime": "2025-11-03T20:30:45",
"codeNo": "MYNM5JHA",
"machineId": "rr3",
"dateFolder": "20251103",
"images": {
"homepage": "20251103/MYNM5JHA/homepage.png",
"first-reward": "20251103/MYNM5JHA/first-reward.png",
"mid-reward": "20251103/MYNM5JHA/mid-reward.png"
// "end-reward" 下载失败,未保存
},
"totalCount": 3 // 成功保存3张
}
数据库记录
成功数量会记录在 completion_images 字段中:
SELECT
code_no,
JSON_EXTRACT(completion_images, '$.totalCount') as saved_count,
completion_images_saved_at
FROM link_task
WHERE code_no = 'MYNM5JHA';
-- 结果:
-- code_no: MYNM5JHA
-- saved_count: 3
-- completion_images_saved_at: 2025-11-03 20:30:45
🔍 故障排查
检查某个任务的图片保存情况
# 查看日志
grep "codeNo=MYNM5JHA" logs/server.log | grep "图片"
# 查看文件系统
ls -lh completion-images/$(date +%Y%m%d)/MYNM5JHA/
# 查询数据库
mysql> SELECT code_no,
JSON_EXTRACT(completion_images, '$.totalCount') as count,
completion_images
FROM link_task
WHERE code_no = 'MYNM5JHA'\G
常见失败原因
| 错误类型 | 说明 | 重试是否有效 | 解决方案 |
|---|---|---|---|
| Connection timeout | 网络超时 | ✅ 有效 | 自动重试通常能解决 |
| 404 Not Found | 图片不存在 | ❌ 无效 | 检查脚本端是否生成图片 |
| 500 Server Error | 脚本端错误 | ⚠️ 部分有效 | 检查脚本端服务状态 |
| Permission denied | 文件权限错误 | ❌ 无效 | 检查目录权限 |
| Disk full | 磁盘空间不足 | ❌ 无效 | 清理磁盘空间 |
📈 优化建议
1. 监控重试率
-- 统计图片保存成功率
SELECT
DATE(completion_images_saved_at) as date,
COUNT(*) as total_tasks,
SUM(CASE
WHEN JSON_EXTRACT(completion_images, '$.totalCount') = 4
THEN 1 ELSE 0
END) as all_4_images,
SUM(CASE
WHEN JSON_EXTRACT(completion_images, '$.totalCount') < 4
THEN 1 ELSE 0
END) as partial_images,
ROUND(SUM(CASE
WHEN JSON_EXTRACT(completion_images, '$.totalCount') = 4
THEN 1 ELSE 0
END) * 100.0 / COUNT(*), 2) as success_rate
FROM link_task
WHERE completion_images_saved_at IS NOT NULL
GROUP BY DATE(completion_images_saved_at)
ORDER BY date DESC;
2. 告警阈值
建议设置告警:
- 如果成功率 < 80%,发送告警
- 如果某个图片重试率 > 50%,检查该图片源
3. 性能调优
# application.yml - 可调整的参数
completion:
image:
retry:
max-attempts: 3 # 最大重试次数
delay-ms: 500 # 重试延迟(毫秒)
timeout-seconds: 10 # 单次下载超时
⚡ 性能影响
最佳情况(所有图片一次成功)
- 总耗时: 约 2-4秒(4张图片并发下载)
- 网络请求: 4次
一般情况(有1-2次重试)
- 总耗时: 约 5-8秒
- 网络请求: 4-8次
最坏情况(某些图片多次重试)
- 总耗时: 约 10-15秒
- 网络请求: 10-16次
- 成功保存: 3-4张图片
🎉 优势
- 高成功率: 双层重试机制大幅提升成功率
- 详细日志: 每次重试都有日志记录,便于排查
- 容错处理: 部分失败不影响整体
- 异步执行: 不阻塞任务完成主流程
📋 监控指标
建议监控以下指标:
- ✅ 图片保存总成功率
- ✅ 每张图片的成功率
- ✅ 平均重试次数
- ✅ 平均保存耗时
- ✅ 失败原因分布
更新时间: 2025-11-03
重试次数: 每张图片最多3次
重试延迟: 500毫秒
状态: ✅ 已实现