65 lines
2 KiB
TypeScript
65 lines
2 KiB
TypeScript
import type {
|
|
WorkerJobErrorShape,
|
|
WorkerJobState,
|
|
WorkerOperationKind,
|
|
WorkerOperationRequest,
|
|
WorkerOperationState,
|
|
} from '../api-contracts';
|
|
|
|
export function isTerminalStatus(status: WorkerJobState): boolean {
|
|
return status === 'succeeded' || status === 'failed';
|
|
}
|
|
|
|
export function isInflightStatus(status: WorkerJobState): boolean {
|
|
return status === 'queued' || status === 'running';
|
|
}
|
|
|
|
export function createErrorShape(error: unknown): WorkerJobErrorShape {
|
|
if (error && typeof error === 'object' && 'message' in error && typeof (error as { message: unknown }).message === 'string') {
|
|
return { message: (error as { message: string }).message };
|
|
}
|
|
return { message: String(error) };
|
|
}
|
|
|
|
export function buildQueuedState(input: {
|
|
request: WorkerOperationRequest;
|
|
opId: string;
|
|
jobId: string;
|
|
queuedAt: number;
|
|
}): WorkerOperationState {
|
|
return {
|
|
opId: input.opId,
|
|
opKey: input.request.opKey,
|
|
kind: input.request.kind,
|
|
jobId: input.jobId,
|
|
status: 'queued',
|
|
queuedAt: input.queuedAt,
|
|
updatedAt: input.queuedAt,
|
|
};
|
|
}
|
|
|
|
export function explainReplacementReason(input: {
|
|
current: WorkerOperationState;
|
|
requestKind: WorkerOperationKind;
|
|
now: number;
|
|
opStaleMs: number;
|
|
}): string {
|
|
if (input.current.kind !== input.requestKind) return 'kind_mismatch';
|
|
const ageMs = input.now - input.current.updatedAt;
|
|
if (isInflightStatus(input.current.status) && ageMs > input.opStaleMs) return 'stale_running';
|
|
if (input.current.status === 'failed') return 'failed_prior';
|
|
return `status_${input.current.status}`;
|
|
}
|
|
|
|
export function shouldReuseExistingOperation(input: {
|
|
current: WorkerOperationState;
|
|
requestKind: WorkerOperationKind;
|
|
now: number;
|
|
opStaleMs: number;
|
|
}): boolean {
|
|
if (input.current.kind !== input.requestKind) return false;
|
|
if (input.current.status === 'succeeded') return true;
|
|
if (!isInflightStatus(input.current.status)) return false;
|
|
const ageMs = input.now - input.current.updatedAt;
|
|
return ageMs <= input.opStaleMs;
|
|
}
|