task-55: 采集进度心跳改为节流/合并写,窗口内心跳只更新内存态不落库,窗口到期或任务结束路径强制持久化,避免高频 task UPDATE

This commit is contained in:
2026-08-30 16:55:37 +08:00
parent 5776217c2c
commit e7828dc926
2 changed files with 335 additions and 0 deletions
@@ -165,6 +165,17 @@ public class CollectDataService {
@Value("${aiimage.collect-data.max-chunk-rows:0}")
private Integer maxChunkRows;
/** 进度统计节流窗口(毫秒):窗口内 changed 心跳合并写,避免高频 task UPDATE。0 关闭节流。 */
@Value("${aiimage.collect-data.progress-throttle-millis:15000}")
private long progressThrottleMillis;
/** 进度统计脏数据兜底窗口(毫秒):窗口到期后即使心跳未变化也强制刷新一次。0 关闭。 */
@Value("${aiimage.collect-data.progress-dirty-window-millis:30000}")
private long progressDirtyWindowMillis;
/** 上次进度统计实际落库时间戳(任务级,单机内存态;无锁竞争风险由任务分布式锁兜底)。 */
private long lastProgressFlushMillis;
/** 采集源文件大小上限。0/负值回退默认 50MB,防止解析无界增长。 */
private long resolveMaxSourceFileBytes() {
Long configured = maxSourceFileBytes;
@@ -425,14 +436,37 @@ public class CollectDataService {
changed = true;
}
if (!changed) {
// 内容未变化:仅当脏数据兜底窗口到期时才强制刷新一次,
// 否则零 UPDATE(重复心跳幂等)。
if (!shouldForceProgressFlush()) {
return;
}
} else if (shouldThrottleProgressFlush()) {
// 节流窗口内:合并写(只更新内存态、不落库),窗口到期后统一持久化。
return;
}
persistStats(task, stats);
task.setUpdatedAt(LocalDateTime.now());
fileTaskMapper.updateById(task);
lastProgressFlushMillis = System.currentTimeMillis();
}
}
/**
* 节流判定:progressThrottleMillis>0 且距上次实际落库未超过窗口 → 合并写(跳过 UPDATE)。
* progressThrottleMillis<=0 视为关闭节流,恒返回 false(每次心跳都落库,兼容旧行为)。
*/
private boolean shouldThrottleProgressFlush() {
return progressThrottleMillis > 0
&& System.currentTimeMillis() - lastProgressFlushMillis < progressThrottleMillis;
}
/** 脏数据兜底判定:progressDirtyWindowMillis>0 且距上次实际落库超过窗口 → 强制刷新一次。 */
private boolean shouldForceProgressFlush() {
return progressDirtyWindowMillis > 0
&& System.currentTimeMillis() - lastProgressFlushMillis >= progressDirtyWindowMillis;
}
@Scheduled(cron = "${aiimage.collect-data.stale-check-cron:*/30 * * * * *}")
public void finalizeStaleTasks() {
long timeoutMinutes = Math.max(1L, staleTimeoutMinutes);