Overview
The PollingHelper class provides a robust polling mechanism with features like exponential backoff, jitter, timeout controls, and stop conditions. Perfect for polling APIs, checking job status, waiting for async operations, and implementing retry logic.
Import
import { PollingHelper , createPoller } from 'bytekit' ;
Usage
Basic Polling
const poller = new PollingHelper (
async () => {
const response = await fetch ( '/api/status' );
return response . json ();
},
{
interval: 2000 , // Poll every 2 seconds
maxAttempts: 10 ,
stopCondition : ( result ) => result . status === 'complete'
}
);
const result = await poller . start ();
if ( result . success ) {
console . log ( 'Job completed:' , result . result );
} else {
console . error ( 'Polling failed:' , result . error );
}
Exponential Backoff
const result = await PollingHelper . pollWithBackoff (
async () => checkJobStatus ( jobId ),
{
interval: 1000 , // Start at 1 second
backoffMultiplier: 2 , // Double interval each time
maxBackoffInterval: 30000 , // Cap at 30 seconds
maxAttempts: 10 ,
stopCondition : ( status ) => status . done
}
);
// Polling intervals: 1s, 2s, 4s, 8s, 16s, 30s, 30s...
With Jitter
const poller = new PollingHelper ( fetchData , {
interval: 5000 ,
jitter: true , // Add ±10% random jitter
maxAttempts: 20
});
// Or custom jitter percentage
const poller2 = new PollingHelper ( fetchData , {
interval: 5000 ,
jitter: 25 , // ±25% jitter
maxAttempts: 20
});
With Attempt Timeout
const poller = new PollingHelper (
async () => {
// Each attempt times out after 5 seconds
return await fetchWithLongOperation ();
},
{
interval: 10000 ,
attemptTimeout: 5000 , // 5 second timeout per attempt
maxAttempts: 5 ,
retryOnError: true
}
);
const result = await poller . start ();
Abort Polling
const poller = new PollingHelper ( fetchData , {
interval: 2000 ,
maxDuration: 60000 // 1 minute max
});
const resultPromise = poller . startWithAbort ();
// Abort from another location
setTimeout (() => {
poller . abort ();
}, 10000 ); // Abort after 10 seconds
const result = await resultPromise ;
if ( ! result . success ) {
console . log ( 'Polling aborted' );
}
Callbacks and Monitoring
const poller = new PollingHelper ( checkStatus , {
interval: 3000 ,
maxAttempts: 10 ,
onAttempt : ( attempt , result , error ) => {
if ( error ) {
console . log ( `Attempt ${ attempt } failed:` , error );
} else {
console . log ( `Attempt ${ attempt } result:` , result );
}
},
onSuccess : ( result , attempts ) => {
console . log ( `Success after ${ attempts } attempts:` , result );
},
onError : ( error , attempts ) => {
console . error ( `Failed after ${ attempts } attempts:` , error );
}
});
const result = await poller . start ();
Stop on Condition
interface JobStatus {
id : string ;
status : 'pending' | 'processing' | 'complete' | 'failed' ;
progress : number ;
}
const result = await PollingHelper . poll < JobStatus >(
async () => await getJobStatus ( jobId ),
{
interval: 2000 ,
maxAttempts: 30 ,
stopCondition : ( status ) => {
// Stop when complete or failed
return status . status === 'complete' || status . status === 'failed' ;
}
}
);
if ( result . success && result . result ?. status === 'complete' ) {
console . log ( 'Job completed successfully' );
}
API Reference
Constructor
options
PollingOptions<T>
default: "{}"
Polling configuration options Polling interval in milliseconds
Maximum number of polling attempts
Maximum polling duration in milliseconds
Multiplier for exponential backoff (1 = no backoff)
Maximum interval for backoff in milliseconds
Function to determine if polling should stop
jitter
boolean | number
default: "false"
Add random jitter (true = 10%, number = custom %)
Timeout for each individual attempt in milliseconds
Whether to continue polling on errors
Base for exponential backoff calculation
onAttempt
(attempt: number, result?: T, error?: Error) => void
Callback for each polling attempt
onSuccess
(result: T, attempts: number) => void
Callback on successful completion
onError
(error: Error, attempts: number) => void
Callback on error
Methods
start
Start polling and return result when complete.
return
Promise<PollingResult<T>>
Promise resolving to polling result interface PollingResult < T > {
success : boolean ;
result ?: T ;
error ?: Error ;
attempts : number ;
duration : number ;
metrics ?: {
minResponseTime : number ;
maxResponseTime : number ;
avgResponseTime : number ;
};
}
const result = await poller . start ();
if ( result . success ) {
console . log ( `Completed in ${ result . duration } ms after ${ result . attempts } attempts` );
}
startWithAbort
Start polling with ability to abort.
return
Promise<PollingResult<T>>
Promise resolving to polling result
const resultPromise = poller . startWithAbort ();
// Later: poller.abort();
const result = await resultPromise ;
abort
Abort ongoing polling operation.
Static Methods
poll
Convenience method for one-off polling.
options
PollingOptions<T>
default: "{}"
Polling options
return
Promise<PollingResult<T>>
Polling result
const result = await PollingHelper . poll (
async () => checkStatus (),
{ interval: 2000 , maxAttempts: 10 }
);
pollWithBackoff
Convenience method for polling with exponential backoff.
options
PollingOptions<T>
default: "{}"
Polling options (backoffMultiplier defaults to 2)
return
Promise<PollingResult<T>>
Polling result
pollWithLinearBackoff
Convenience method for polling with linear backoff.
options
PollingOptions<T>
default: "{}"
Polling options (backoffMultiplier defaults to 1.5)
return
Promise<PollingResult<T>>
Polling result
Types
PollingOptions
interface PollingOptions < T = unknown > {
interval ?: number ;
maxAttempts ?: number ;
maxDuration ?: number ;
backoffMultiplier ?: number ;
maxBackoffInterval ?: number ;
stopCondition ?: ( result : T ) => boolean ;
onAttempt ?: ( attempt : number , result ?: T , error ?: Error ) => void ;
onSuccess ?: ( result : T , attempts : number ) => void ;
onError ?: ( error : Error , attempts : number ) => void ;
jitter ?: boolean | number ;
attemptTimeout ?: number ;
retryOnError ?: boolean ;
exponentialBase ?: number ;
}
PollingResult
interface PollingResult < T = unknown > {
success : boolean ;
result ?: T ;
error ?: Error ;
attempts : number ;
duration : number ;
metrics ?: {
minResponseTime : number ;
maxResponseTime : number ;
avgResponseTime : number ;
};
}
Use Cases
API Job Status
async function waitForJob ( jobId : string ) {
const result = await PollingHelper . pollWithBackoff (
async () => {
const response = await fetch ( `/api/jobs/ ${ jobId } ` );
return response . json ();
},
{
interval: 1000 ,
maxAttempts: 20 ,
stopCondition : ( job ) => job . status !== 'pending'
}
);
return result . result ;
}
Health Check
const healthCheck = await PollingHelper . poll (
async () => {
const response = await fetch ( '/health' );
if ( ! response . ok ) throw new Error ( 'Service unhealthy' );
return true ;
},
{
interval: 5000 ,
maxAttempts: 12 , // 1 minute total
retryOnError: true
}
);
Resource Availability
const resourceReady = await PollingHelper . poll (
async () => await checkResourceExists ( resourceId ),
{
interval: 2000 ,
maxDuration: 30000 , // 30 second timeout
stopCondition : ( exists ) => exists === true
}
);
Best Practices
Always set maxAttempts or maxDuration to prevent infinite polling
Use exponential backoff for external APIs to reduce load
Add jitter when polling shared resources to avoid thundering herd
Set attemptTimeout for long-running operations
Use stopCondition for early exit on success conditions