Files
openclaw/src/infra/backoff.ts
EVA c15b295a85 Run context-engine turn maintenance as idle-aware background work (#65233)
Merged via squash.

Prepared head SHA: e9f6c679ba
Co-authored-by: 100yenadmin <239388517+100yenadmin@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-13 06:50:22 -07:00

60 lines
1.4 KiB
TypeScript

export type BackoffPolicy = {
initialMs: number;
maxMs: number;
factor: number;
jitter: number;
};
export function computeBackoff(policy: BackoffPolicy, attempt: number) {
const base = policy.initialMs * policy.factor ** Math.max(attempt - 1, 0);
const jitter = base * policy.jitter * Math.random();
return Math.min(policy.maxMs, Math.round(base + jitter));
}
export async function sleepWithAbort(ms: number, abortSignal?: AbortSignal) {
if (ms <= 0) {
return;
}
await new Promise<void>((resolve, reject) => {
let settled = false;
let timer: ReturnType<typeof setTimeout> | null = null;
const onAbort = () => {
if (settled) {
return;
}
settled = true;
if (timer) {
clearTimeout(timer);
timer = null;
}
if (abortSignal) {
abortSignal.removeEventListener("abort", onAbort);
}
reject(new Error("aborted", { cause: abortSignal?.reason ?? new Error("aborted") }));
};
if (abortSignal) {
abortSignal.addEventListener("abort", onAbort, { once: true });
if (abortSignal.aborted) {
onAbort();
return;
}
}
timer = setTimeout(() => {
settled = true;
if (abortSignal) {
abortSignal.removeEventListener("abort", onAbort);
}
timer = null;
resolve();
}, ms);
if (abortSignal) {
if (abortSignal.aborted) {
onAbort();
}
}
});
}