@comake/skl-js-engine
Version:
Standard Knowledge Language Javascript Engine
115 lines (103 loc) • 3.41 kB
text/typescript
/**
* Utility for polling operations with timeout
*/
import { Logger } from '../../../logger';
/**
* Options for polling with timeout
*/
export interface PollingOptions {
/** Total timeout in milliseconds */
timeout: number;
/** Polling interval in milliseconds (default: 100ms) */
interval?: number;
/** Initial delay before starting polling in milliseconds (default: 0ms) */
initialDelay?: number;
}
/**
* Poll a condition function until it returns true or timeout is reached
*
* @param conditionFn - Function that returns true when condition is met, false to continue polling
* @param options - Polling configuration
* @param timeoutErrorMessage - Custom error message for timeout
* @returns Promise that resolves when condition is met or rejects on timeout
*
* @example
* ```typescript
* // Wait for process to be ready
* await pollUntilTrue(
* () => process.isRunning(),
* { timeout: 5000, interval: 100 },
* 'Process failed to start'
* );
* ```
*/
export async function pollUntilTrue(
conditionFn: () => boolean | Promise<boolean>,
options: PollingOptions,
timeoutErrorMessage: string
): Promise<void> {
const { timeout, interval = 100, initialDelay = 0 } = options;
const startTime = Date.now();
// Initial delay if specified
if (initialDelay > 0) {
await new Promise<void>((resolve: () => void): NodeJS.Timeout => setTimeout(resolve, initialDelay));
}
while (Date.now() - startTime < timeout) {
try {
// Condition met!
if (await conditionFn()) {
return;
}
} catch (error: unknown) {
Logger.getInstance().error(new Error(`${timeoutErrorMessage} after ${timeout}ms`), error);
}
// Wait before next check
await new Promise<void>((resolve: () => void): NodeJS.Timeout => setTimeout(resolve, interval));
}
// Timeout reached
throw new Error(`${timeoutErrorMessage} after ${timeout}ms`);
}
/**
* Poll an async operation until it succeeds or timeout is reached
*
* @param operationFn - Async function to retry until it succeeds
* @param options - Polling configuration
* @param timeoutErrorMessage - Custom error message for timeout
* @returns Promise that resolves with operation result or rejects on timeout
*
* @example
* ```typescript
* // Wait for ping to succeed
* await pollUntilSuccess(
* () => client.ping(),
* { timeout: 10000, interval: 500 },
* 'Failed to connect'
* );
* ```
*/
export async function pollUntilSuccess<T>(
operationFn: () => Promise<T>,
options: PollingOptions,
timeoutErrorMessage: string
): Promise<T> {
const { timeout, interval = 100, initialDelay = 0 } = options;
const startTime = Date.now();
// Initial delay if specified
if (initialDelay > 0) {
await new Promise<void>((resolve: () => void): NodeJS.Timeout => setTimeout(resolve, initialDelay));
}
while (Date.now() - startTime < timeout) {
try {
// Success!
return await operationFn();
} catch (error: unknown) {
Logger.getInstance().error(new Error(`${timeoutErrorMessage} after ${timeout}ms`), error);
// Operation failed, continue polling if we have time
if (Date.now() - startTime < timeout) {
await new Promise<void>((resolve: () => void): NodeJS.Timeout => setTimeout(resolve, interval));
}
}
}
// Timeout reached
throw new Error(`${timeoutErrorMessage} after ${timeout}ms`);
}