Files
FileHost/server/utils/backup/cancel-state.ts
T
2026-10-17 15:08:21 +08:00

65 lines
1.8 KiB
TypeScript

interface JobCancellationState {
requested: Set<string>
controllers: Map<string, AbortController>
}
const CANCELLED_CODE = 'JOB_CANCELLED'
const state = (globalThis as typeof globalThis & {
__pichostJobCancellationState?: JobCancellationState
}).__pichostJobCancellationState ?? {
requested: new Set<string>(),
controllers: new Map<string, AbortController>()
}
;(globalThis as typeof globalThis & {
__pichostJobCancellationState?: JobCancellationState
}).__pichostJobCancellationState = state
export function createJobCancelledError(): Error {
const error = new Error('任务已取消')
error.name = CANCELLED_CODE
return error
}
export function isJobCancelledError(error: unknown): boolean {
return error instanceof Error && error.name === CANCELLED_CODE
}
export function beginJobCancellationScope(jobId: string): void {
state.requested.delete(jobId)
state.controllers.get(jobId)?.abort()
state.controllers.set(jobId, new AbortController())
}
export function endJobCancellationScope(jobId: string): void {
state.controllers.delete(jobId)
state.requested.delete(jobId)
}
export function requestJobCancellation(jobId: string): void {
state.requested.add(jobId)
state.controllers.get(jobId)?.abort(createJobCancelledError())
}
export function isJobCancellationRequested(jobId: string): boolean {
return state.requested.has(jobId)
}
export function getJobAbortSignal(jobId: string): AbortSignal {
return state.controllers.get(jobId)?.signal ?? new AbortController().signal
}
export function getJobOperationSignal(
jobId: string,
timeoutMs: number
): AbortSignal {
return AbortSignal.any([
getJobAbortSignal(jobId),
AbortSignal.timeout(timeoutMs)
])
}
export function throwIfJobCancellationRequested(jobId: string): void {
if (isJobCancellationRequested(jobId)) throw createJobCancelledError()
}