spaced-loop
v1.0.0
Published
Invoke a callback every so often, with an increasing delay upon failure and a max number of retries
Readme
spaced-loop
Standard loop where a user-defined callback is called every so often. If the callback throws an error, the delay between callback invocations is increased up to a maximum, and reset to its initial value upon a successful invocation. Useful when you don't want to spam an API with fetch requests, or wait a while after a failure before trying again.
Install
npm install spaced-loopUsage
import SpacedLoop from 'spaced-loop';
const loop = new SpacedLoop({
cb: (loop) => {
console.log(
`callback invoked! Throwing an error to increase the delay to ${loop.currentDelayMs + 2000}!`,
);
throw new Error('Something bad happened');
},
onError: (loop, error) => {
console.error(error);
console.log(
`attempt ${loop.consecutiveErrors}/${loop.maxConsecutiveErrors} failed`,
);
},
delayStepMs: 2000,
maxDelayMs: 20000,
maxConsecutiveErrors: 5,
});
await loop.body;
console.log('loop finished running');Constructor Parameters
The SpacedLoop constructor takes an object that can contain the following properties:
| Property | Type | Purpose |
| -------- | ---- | ------- |
| cb | function (loop: SpacedLoop): void | The callback that will run every iteration of the loop. If this callback throws an error, the loop will run the onError callback and add the delayStepMs onto the current delay time. If this callback is successful, the current delay time will be reset to its original value. This callback is passed a reference to the loop. |
| onError | function (loop: SpacedLoop, error: unknown): void | The callback that will run in response to any errors thrown by the cb callback. You could use this to log errors, etc. This callback is passed a reference to the loop and the error that was thrown by the cb callback. |
| onMaxErrors | function (loop: SpacedLoop, error: unknown): void | The callback that will run in response to the max consecutive errors being reached. You could use this to print a message after reaching the max errors, or take another course of action. This callback is passed a reference to the loop and the last error thrown by the cb callback. |
| delayStepMs | number | The initial loop delay duration will be set to this value. Each time the loop encounters an error, this value will be added onto the loop delay duration. Defaults to 10 seconds. |
| maxDelayMs | number | The maximum loop delay duration. Defaults to 60 seconds. |
| maxConsecutiveErrors | number | So you can have the loop exit after a number of consecutive errors. E.g. if you want to retry a fetch request a maximum number of times before exiting, use this. Defaults to zero, which means there is no limit to the number of consecutive errors. |
| ignoreRunTime | boolean | If this is set to false, the delay at the end of each iteration will be reduced to compensate for the time taken to execute the cb callback. So if the callback takes 500ms to execute and the current delay time is 600ms, the delay will only be 100ms, so the whole loop iteration will end up taking 600ms in total. If the callback takes 200ms or longer to execute and the current delay time is 200ms, the delay will be skipped entirely. Defaults to true. |
SpacedLoop Members
The returned loop (which is also passed into the cb and onError callbacks as in the above example) contains the following members:
| Property | Type | Purpose |
| -------- | ---- | ------- |
| body | Promise<void> | A promise that resolves once the loop has been exited. Await this in order to run some code once the loop has finished. |
| currentDelayMs | number | Current minimum delay time until the next loop starts. If the callback takes a long time to execute, it is possible the time taken will exceed this value, hence current minimum delay time. |
| consecutiveErrors | number | The number of consecutive errors thrown by loop iterations. Resets to zero when a loop iteration runs without throwing an error. Can be used to make logs, e.g. "retry 1/5", etc. |
| maxConsecutiveErrors | number | The max number of consecutive errors before the loop exits automatically. If this is set to zero, then the loop will continue indefinitely, regardless of the number of errors thrown. Can be used to make logs, e.g. "retry 1/5", etc. |
| exit | function (): void | This method causes the loop to exit after the current iteration has finished. That includes the wait time at the end of each iteration, so the promise stored in body will not resolve until the current wait period has elapsed. Since a reference to the loop is passed to all callbacks, the loop can be exited from within any of the callbacks by invoking this method. |
