Library provides RxJS operator that can do polling on any completed source.
rxjs-poll features:
- Two types of polling;
repeat
andinterval
- Delay/retry can be a static, random or dynamic number
- Any delay/backoff strategy you can think of
- Background mode (browser only) to pause/resume polling on page visibility
- Consecutive rule for different retry attempts approach
- Config input guard for unexpected values
- Supports browser and node environment
- Compatible with RxJS v7+
- Provides cjs and esm
npm install rxjs-poll --save
Let's say that you want to poll fun facts about cats. This is the request:
import { ajax } from 'rxjs/ajax';
import { map } from 'rxjs';
interface CatFact {
fact: string;
length: number;
}
const request$ = ajax<CatFact>({ url: 'https://catfact.ninja/fact' }).pipe(
map(({ response }) => response)
);
Plug and play, just add an operator to your pipe and poll.
import { poll } from 'rxjs-poll';
import { takeWhile } from 'rxjs';
request$
.pipe(
poll(),
takeWhile(({ length }) => length < 200, true)
)
.subscribe({ next: console.log });
With a config file you can customize polling to your specific needs.
import { poll } from 'rxjs-poll';
import { takeWhile } from 'rxjs';
request$
.pipe(
poll({
type: 'interval', // Drops uncompleted source after delay
retries: Infinity, // Will never throw
delay: [1000, 2000], // Random delay with min and max values
}),
takeWhile(({ length }) => length < 200, true)
)
.subscribe({ next: console.log });
Use delay function with provided state when you need unique delay or backoff strategies for polling/retrying.
import { poll } from 'rxjs-poll';
import { takeWhile } from 'rxjs';
request$
.pipe(
poll({
retries: 6,
delay: ({ value, error, consecutiveRetries }) => {
const delay = 1000;
if (error) {
// Exponential backoff strategy
// With 6 retries, throws after ~1min of consecutive errors
return Math.pow(2, consecutiveRetries - 1) * delay;
}
// Faster polls for shorter facts
return value.length < 100 ? delay * 0.3 : delay;
},
}),
takeWhile(({ length }) => length < 200, true)
)
.subscribe({ next: console.log });
It is a mono type operator function that will poll once a source completes. If the source is not completed, the operator will wait until that happens. First emission is sent immediately, then the polling will start. Values will emit until stopped by the user.
source$.pipe(poll({ type: 'repeat', retries: 10 }));
Configuration object used to setup polling mechanism. Any non-assigned, negative or invalid values will be replaced with default configuration values.
interface PollConfig {
/**
* Poller type
*
* repeat - polls after current source completes
* interval - polls in intervals and drops source that is not complete
*/
type: 'repeat' | 'interval';
/**
* Delay between polls and retries
*
* Use static or random number with min and max values. If you need
* dynamic number, use function and return either static or random number.
* Numbers should be positive and finate.
*/
delay:
| number
| [number | number]
| ((state: PollState) => number | [number | number]);
/**
* Number of retries
*
* Number of retries before it will throw. Number should be positive, but
* it can be Infinity if you don't care about errors.
*/
retries: number;
/**
* Retry's counting approach
*
* If true, then only consecutive error count will be checked against
* retires. Consecutive error count is reset to 0 on successful response.
* If false, then any number of errors will be checked against retires.
*/
isConsecutiveRule: boolean;
/**
* Pause/resume polling - browser only
*
* Polling can be paused/resumed depending on page visibility.
* ex. If this is false and you switch to another tab, polling is paused.
* Once you go back, polling resumes.
*/
isBackgroundMode: boolan;
}
const config: PollConfig = {
type: 'repeat',
delay: 1000,
retries: 3,
isConsecutiveRule: true,
isBackgroundMode: false,
};
Provided as argument of delay function. Use it to set delay for polls and retries.
interface PollState<T> {
polls: number; // current count of successful polls
retries: number; // current count of retries
consecutiveRetries: number; // current count of consecutive retries
value: T; // value emitted from the source
error: any | null; // "any" when retrying and "null" when polling
}
// polls + retries = total attempts
This library is inspired by the rx-polling that creates Observable for polling.