Skip to content

Instantly share code, notes, and snippets.

@whiteinge
Last active April 1, 2021 23:52
Show Gist options
  • Save whiteinge/4f6648083c97191f2114c5463b41323c to your computer and use it in GitHub Desktop.
Save whiteinge/4f6648083c97191f2114c5463b41323c to your computer and use it in GitHub Desktop.
An RxJS poller with incremental back-off as a let-function
import { TimeoutError, timer } from 'rxjs'
import { AjaxTimeoutError } from 'rxjs/ajax'
import {
delay,
filter,
flatMap,
repeatWhen,
retryWhen,
scan,
timeout,
} from 'rxjs/operators'
/**
Repeat an observable on a regular interval.
Wait for one poll to end before starting another.
Gradually increase the poll interval if a poll times out.
Usage:
// Repeat SomeObservable; must complete to trigger a repeat.
SomeObservable.pipe(
makePoller(),
// Repeats indefinitely without end condition.
takeUntil(endCondition),
)
**/
export const makePoller = ({
intervalms = 10000,
timeoutms = 30000,
backoffIncrementms = 5000,
backoffMax = 5,
scheduler,
} = {}) => o =>
o.pipe(
repeatWhen(no => no.pipe(delay(intervalms, scheduler))),
timeout(timeoutms, scheduler),
retryWhen(no =>
no.pipe(
filter(x => x instanceof TimeoutError || x instanceof AjaxTimeoutError),
scan(count => count + 1, 0),
flatMap(i => {
const backoff = i < backoffMax ? i * backoffIncrementms : backoffMax * backoffIncrementms
return timer(backoff, scheduler)
}),
),
),
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment