30 lines
2.2 KiB
TypeScript
30 lines
2.2 KiB
TypeScript
import type { BackupJobStatusResponse, CreateBackupRequest } from "@mmapp/contracts/backups"
|
|
import { getBackupJob } from "@/shared/api/backups"
|
|
export function waitForBackupPoll(ms: number, signal: AbortSignal): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
if (signal.aborted) { reject(signal.reason); return }
|
|
const abort = () => { clearTimeout(timer); signal.removeEventListener("abort", abort); reject(signal.reason) }
|
|
const timer = setTimeout(() => { signal.removeEventListener("abort", abort); resolve() }, ms)
|
|
signal.addEventListener("abort", abort, { once: true })
|
|
})
|
|
}
|
|
export async function pollBackupJob(baseUrl: string, jobId: string, target: CreateBackupRequest, options: {
|
|
signal: AbortSignal; onJob?: (job: BackupJobStatusResponse) => void; readJob?: typeof getBackupJob; wait?: typeof waitForBackupPoll; attempts?: number; intervalMs?: number
|
|
}) {
|
|
const signal = AbortSignal.any([options.signal, AbortSignal.timeout(300_000)])
|
|
const readJob = options.readJob ?? getBackupJob, wait = options.wait ?? waitForBackupPoll, attempts = options.attempts ?? 150
|
|
for (let index = 0; index < attempts; index++) {
|
|
signal.throwIfAborted()
|
|
const job = await readJob(baseUrl, jobId, { signal }); signal.throwIfAborted()
|
|
if (job.id !== jobId || JSON.stringify(job.serverIds) !== JSON.stringify(target.serverIds.map(String)) || (job.notes ?? "") !== (target.notes?.trim() ?? "")) throw new Error("Ответ задачи не соответствует выбранным серверам или заметке")
|
|
options.onJob?.(job)
|
|
if (job.status === "done" || job.status === "failed") return job
|
|
if (index + 1 < attempts) await wait(options.intervalMs ?? 1200, signal)
|
|
}
|
|
throw new Error("Время наблюдения истекло. Задача может продолжаться; повторите проверку той же задачи")
|
|
}
|
|
export function backupJobOutcome(job: BackupJobStatusResponse) {
|
|
const uploadFailures = job.created.filter(item => item.uploadError)
|
|
return { fullSuccess: job.status === "done" && job.created.length === job.total && !job.failures.length && !uploadFailures.length, created: job.created.length, deviceFailures: job.failures, uploadFailures }
|
|
}
|