@dfinity/agent
Version:
JavaScript and TypeScript library to interact with the Internet Computer
91 lines • 3.28 kB
JavaScript
import { ProtocolError, TimeoutWaitingForResponseErrorCode } from "../errors.js";
const FIVE_MINUTES_IN_MSEC = 5 * 60 * 1000;
/**
* A best practices polling strategy: wait 2 seconds before the first poll, then 1 second
* with an exponential backoff factor of 1.2. Timeout after 5 minutes.
*/
export function defaultStrategy() {
return chain(conditionalDelay(once(), 1000), backoff(1000, 1.2), timeout(FIVE_MINUTES_IN_MSEC));
}
/**
* Predicate that returns true once.
*/
export function once() {
let first = true;
return async () => {
if (first) {
first = false;
return true;
}
return false;
};
}
/**
* Delay the polling once.
* @param condition A predicate that indicates when to delay.
* @param timeInMsec The amount of time to delay.
*/
export function conditionalDelay(condition, timeInMsec) {
return async (canisterId, requestId, status) => {
if (await condition(canisterId, requestId, status)) {
return new Promise(resolve => setTimeout(resolve, timeInMsec));
}
};
}
/**
* Error out after a maximum number of polling has been done.
* @param count The maximum attempts to poll.
*/
export function maxAttempts(count) {
let attempts = count;
return async (_canisterId, requestId, status) => {
if (--attempts <= 0) {
throw ProtocolError.fromCode(new TimeoutWaitingForResponseErrorCode(`Failed to retrieve a reply for request after ${count} attempts`, requestId, status));
}
};
}
/**
* Throttle polling.
* @param throttleInMsec Amount in millisecond to wait between each polling.
*/
export function throttle(throttleInMsec) {
return () => new Promise(resolve => setTimeout(resolve, throttleInMsec));
}
/**
* Reject a call after a certain amount of time.
* @param timeInMsec Time in milliseconds before the polling should be rejected.
*/
export function timeout(timeInMsec) {
const end = Date.now() + timeInMsec;
return async (_canisterId, requestId, status) => {
if (Date.now() > end) {
throw ProtocolError.fromCode(new TimeoutWaitingForResponseErrorCode(`Request timed out after ${timeInMsec} msec`, requestId, status));
}
};
}
/**
* A strategy that throttle, but using an exponential backoff strategy.
* @param startingThrottleInMsec The throttle in milliseconds to start with.
* @param backoffFactor The factor to multiple the throttle time between every poll. For
* example if using 2, the throttle will double between every run.
*/
export function backoff(startingThrottleInMsec, backoffFactor) {
let currentThrottling = startingThrottleInMsec;
return () => new Promise(resolve => setTimeout(() => {
currentThrottling *= backoffFactor;
resolve();
}, currentThrottling));
}
/**
* Chain multiple polling strategy. This _chains_ the strategies, so if you pass in,
* say, two throttling strategy of 1 second, it will result in a throttle of 2 seconds.
* @param strategies A strategy list to chain.
*/
export function chain(...strategies) {
return async (canisterId, requestId, status) => {
for (const a of strategies) {
await a(canisterId, requestId, status);
}
};
}
//# sourceMappingURL=strategy.js.map