task-31: 连续失败计数

useTaskProgressLoop 轮询循环维护连续失败计数:refreshOnce 成功
(收到响应)归零;失败递增(封顶 100);onError 回调增加第二参数
attempt(0 起),供上层决定退避策略;dispose 后不再上报。

同时把该组合式函数内部 @/ 别名 import 改为相对路径(带 .ts 扩展),
使其可在 node --test 下直接运行(此前无任何测试覆盖该文件)。
新增 8 个测试:递增、成功后归零、收到响应归零、onError 带 attempt、
初始 0、交错、封顶、dispose 清理。
This commit is contained in:
2026-08-31 20:26:31 +08:00
parent 9e224929fb
commit ab55b20edd
2 changed files with 196 additions and 8 deletions
@@ -4,20 +4,20 @@ import {
getTaskPollBackoffMs,
getTaskForegroundRefreshEnabled,
getTaskForegroundRefreshDelayMs,
} from '@/shared/task-progress-config'
import { createCategorizedTimers } from '@/shared/utils/categorized-timers'
} from '../task-progress-config.ts'
import { createCategorizedTimers } from '../utils/categorized-timers.ts'
import {
createTaskPollingBaseline,
type TaskPollingBaseline,
} from '@/shared/task-polling-baseline'
} from '../task-polling-baseline.ts'
import {
createProgressResponseCache,
type ProgressResponseCache,
} from '@/shared/progress-response-cache'
} from '../progress-response-cache.ts'
import {
createTaskPollingCoordinator,
type TaskPollingCoordinator,
} from '@/shared/task-polling-coordinator'
} from '../task-polling-coordinator.ts'
/**
* 通用任务进度轮询组合式函数。
@@ -59,8 +59,11 @@ export interface TaskProgressLoopOptions<TDetail> {
* 若多个任务同一轮到达终态,会被分别回调。
*/
onTerminal?: (taskId: number, detail: TDetail | undefined, status: string) => void | Promise<void>
/** 轮询周期失败时的回调;默认静默 */
onError?: (error: unknown) => void
/**
* 轮询周期失败时的回调;默认静默。
* 第二个参数 attempt 为连续失败计数(0 起,成功后归零),供上层决定退避策略。
*/
onError?: (error: unknown, attempt?: number) => void
/** 自定义轮询间隔;默认根据 document.visibilityState 自适应(5s/30s */
getIntervalMs?: () => number
/**
@@ -138,6 +141,7 @@ export function useTaskProgressLoop<TDetail>(
const inFlight = ref(false)
let pollTimer: number | null = null
let disposed = false
let failureCount = 0
function persist() {
writeIdsToStorage(options.storageKey, taskIds.value)
@@ -204,6 +208,7 @@ export function useTaskProgressLoop<TDetail>(
}
}
taskStatuses.value = nextStatuses
failureCount = 0
for (const event of terminalEvents) {
coordinator?.markTerminal(event.taskId)
remove(event.taskId)
@@ -214,7 +219,11 @@ export function useTaskProgressLoop<TDetail>(
}
}
} catch (error) {
options.onError?.(error)
if (!disposed) {
const attempt = failureCount
failureCount = Math.min(failureCount + 1, 100)
options.onError?.(error, attempt)
}
} finally {
inFlight.value = false
if (baseline) options.onBaseline?.(baseline)