@ai2070/l0
Version:
L0: The Missing Reliability Substrate for AI
201 lines (200 loc) • 5.23 kB
JavaScript
import { RETRY_DEFAULTS } from "../types/retry";
function exponentialBackoff(attempt, baseDelay = RETRY_DEFAULTS.baseDelay, maxDelay = RETRY_DEFAULTS.maxDelay) {
const rawDelay = baseDelay * Math.pow(2, attempt);
const delay = Math.min(rawDelay, maxDelay);
return {
delay,
cappedAtMax: rawDelay > maxDelay,
rawDelay
};
}
function linearBackoff(attempt, baseDelay = RETRY_DEFAULTS.baseDelay, maxDelay = RETRY_DEFAULTS.maxDelay) {
const rawDelay = baseDelay * (attempt + 1);
const delay = Math.min(rawDelay, maxDelay);
return {
delay,
cappedAtMax: rawDelay > maxDelay,
rawDelay
};
}
function fixedBackoff(baseDelay = RETRY_DEFAULTS.baseDelay) {
return {
delay: baseDelay,
cappedAtMax: false,
rawDelay: baseDelay
};
}
function fixedJitterBackoff(baseDelay = RETRY_DEFAULTS.baseDelay, maxDelay = RETRY_DEFAULTS.maxDelay) {
const jitter = Math.random() * baseDelay * 0.5;
const rawDelay = baseDelay + jitter;
const delay = Math.min(Math.floor(rawDelay), maxDelay);
return {
delay,
cappedAtMax: rawDelay > maxDelay,
rawDelay
};
}
function fullJitterBackoff(attempt, baseDelay = RETRY_DEFAULTS.baseDelay, maxDelay = RETRY_DEFAULTS.maxDelay) {
const exponential = baseDelay * Math.pow(2, attempt);
const cappedExponential = Math.min(exponential, maxDelay);
const rawDelay = Math.random() * cappedExponential;
const delay = Math.floor(rawDelay);
return {
delay,
cappedAtMax: exponential > maxDelay,
rawDelay
};
}
function decorrelatedJitterBackoff(attempt, baseDelay = RETRY_DEFAULTS.baseDelay, maxDelay = RETRY_DEFAULTS.maxDelay, previousDelay) {
const prev = previousDelay ?? baseDelay * Math.pow(2, attempt);
const rawDelay = Math.random() * (prev * 3 - baseDelay) + baseDelay;
const delay = Math.min(Math.floor(rawDelay), maxDelay);
return {
delay,
cappedAtMax: rawDelay > maxDelay,
rawDelay
};
}
function calculateBackoff(strategy, attempt, baseDelay = RETRY_DEFAULTS.baseDelay, maxDelay = RETRY_DEFAULTS.maxDelay) {
switch (strategy) {
case "exponential":
return exponentialBackoff(attempt, baseDelay, maxDelay);
case "linear":
return linearBackoff(attempt, baseDelay, maxDelay);
case "fixed":
return fixedBackoff(baseDelay);
case "full-jitter":
return fullJitterBackoff(attempt, baseDelay, maxDelay);
case "fixed-jitter":
return fixedJitterBackoff(baseDelay, maxDelay);
default:
return exponentialBackoff(attempt, baseDelay, maxDelay);
}
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function timeout(ms, message = "Timeout") {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error(message)), ms);
});
}
async function withTimeout(promise, timeoutMs, timeoutMessage) {
return Promise.race([promise, timeout(timeoutMs, timeoutMessage)]);
}
class Timer {
startTime;
endTime;
pauseTime;
totalPausedTime = 0;
/**
* Start the timer
*/
start() {
this.startTime = Date.now();
this.endTime = void 0;
this.pauseTime = void 0;
this.totalPausedTime = 0;
}
/**
* Pause the timer
*/
pause() {
if (!this.startTime || this.pauseTime) return;
this.pauseTime = Date.now();
}
/**
* Resume the timer
*/
resume() {
if (!this.pauseTime) return;
this.totalPausedTime += Date.now() - this.pauseTime;
this.pauseTime = void 0;
}
/**
* Stop the timer
*/
stop() {
if (!this.startTime) return;
if (this.pauseTime) {
this.resume();
}
this.endTime = Date.now();
}
/**
* Get elapsed time in milliseconds
*/
elapsed() {
if (!this.startTime) return 0;
const end = this.endTime ?? Date.now();
const paused = this.pauseTime ? this.totalPausedTime + (Date.now() - this.pauseTime) : this.totalPausedTime;
return end - this.startTime - paused;
}
/**
* Reset the timer
*/
reset() {
this.startTime = void 0;
this.endTime = void 0;
this.pauseTime = void 0;
this.totalPausedTime = 0;
}
/**
* Check if timer is running
*/
isRunning() {
return !!this.startTime && !this.endTime && !this.pauseTime;
}
/**
* Check if timer is paused
*/
isPaused() {
return !!this.pauseTime;
}
}
function debounce(fn, delay) {
let timeoutId = null;
return (...args) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
fn(...args);
timeoutId = null;
}, delay);
};
}
function throttle(fn, delay) {
let lastCall = 0;
let timeoutId = null;
return (...args) => {
const now = Date.now();
const timeSinceLastCall = now - lastCall;
if (timeSinceLastCall >= delay) {
lastCall = now;
fn(...args);
} else if (!timeoutId) {
timeoutId = setTimeout(() => {
lastCall = Date.now();
fn(...args);
timeoutId = null;
}, delay - timeSinceLastCall);
}
};
}
export {
Timer,
calculateBackoff,
debounce,
decorrelatedJitterBackoff,
exponentialBackoff,
fixedBackoff,
fixedJitterBackoff,
fullJitterBackoff,
linearBackoff,
sleep,
throttle,
timeout,
withTimeout
};
//# sourceMappingURL=timers.js.map