Skip to content

Commit e3872f8

Browse files
authored
#14 (#15) add exponential back-off support
1 parent 73323a7 commit e3872f8

File tree

14 files changed

+589
-2358
lines changed

14 files changed

+589
-2358
lines changed

.npmignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ coverage
2121

2222
# source files
2323
src
24+
CHANGELOG.md
25+
src/test/
2426
test
2527
scripts
2628

.nycrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "@istanbuljs/nyc-config-typescript",
3+
"exclude": ["src/test/**"],
4+
"sourceMap": false,
5+
"produce-source-map": false
6+
}

.travis.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
language: node_js
2+
23
node_js:
34
- "6"
4-
- "7"
55
- "8"
6-
- "9"
76
- "10"
7+
- "12"
8+
- "14"
9+
810
install:
911
- npm install
12+
1013
script:
1114
- npm run build && npm run cover
15+
1216
after_script: "cat coverage/lcov.info | node_modules/coveralls/bin/coveralls.js"
1317

1418
jobs:

CHANGELOG.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,21 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44
## Development
55
- nothing yet
66

7-
## [v2.0.0](https://github.com/regevbr/busywait.js/releases/tag/v2.0.0)
7+
## [v3.0.0](https://github.com/regevbr/busywait.js/compare/v2.0.0...v3.0.0)
8+
### Breaking changes
9+
- Errors are now an instance of `Error` and not plain strings
10+
- Options type was modified
11+
- Return type was modified
12+
### Added
13+
- Exponential backoff (with optional full jitter) support
14+
- Added to the result, the time it took to finish
15+
- Added delay information to the checked function call
16+
### Fixed
17+
- Better type inference
18+
- Updated readme
19+
- Updated all dependencies to the latest versions
20+
21+
## [v2.0.0](https://github.com/regevbr/busywait.js/compare/v1.1.0...v2.0.0)
822
### Breaking changes
923
- Removed redundant export methods
1024
- Sync check functions will be considered as failed only if they throw error
@@ -14,5 +28,3 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1428
### Fixed
1529
- Updated readme
1630
- Updated all dependencies to the latest versions
17-
18-
[v2.0.0]: https://github.com/PruvoNet/squiss-ts/compare/v1.1.0...v2.0.0

README.md

Lines changed: 109 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,116 @@
1010
Simple Async busy wait module for Node.JS
1111

1212
## Main features
13-
- Simple api to busy wait for a desired outcome
14-
- Slim library (65 lines of code, no dependencies)
13+
- Simple api to busy wait for a desired outcome
14+
- Exponential backoff (with optional full jitter) support
15+
- Slim library (single file, 100 lines of code, no dependencies)
1516
- Full typescript support
1617

1718
## Quick example
1819
```typescript
1920
import { busywait } from 'busywait';
20-
import {IBusyWaitResult} from 'busywait';
2121

2222
const waitUntil = Date.now() + 2500;
23-
const checkFn = (iteration: number): Promise<string> => {
24-
return new Promise((resolve, reject) => {
25-
console.log('running iteration', iteration);
26-
if (Date.now() > waitUntil) {
27-
return resolve('success');
28-
} else {
29-
return reject();
30-
}
31-
});
23+
24+
const checkFn = async (iteration: number, delay: number): Promise<string> => {
25+
console.log(`Running iteration ${iteration} after delay of ${delay}ms`);
26+
if (Date.now() > waitUntil) {
27+
return `success`;
28+
}
29+
throw new Error('custom error');
30+
};
31+
32+
(async () => {
33+
const result = await busywait(checkFn, {
34+
sleepTime: 500,
35+
maxChecks: 20,
36+
})
37+
console.log(`Finished after ${result.backoff.time}ms (${result.backoff.iterations} iterations) with result ${result.result}`);
38+
})();
39+
```
40+
41+
Will result in:
42+
``` bash
43+
Running iteration 1 after delay of 0ms
44+
Running iteration 2 after delay of 500ms
45+
Running iteration 3 after delay of 500ms
46+
Running iteration 4 after delay of 500ms
47+
Running iteration 5 after delay of 500ms
48+
Running iteration 6 after delay of 500ms
49+
Finished after 2511ms (6 iterations) with result success
50+
```
51+
52+
### Exponential backoff
53+
54+
```typescript
55+
import { busywait } from 'busywait';
56+
57+
const waitUntil = Date.now() + 2500;
58+
59+
const checkFn = async (iteration: number, delay: number): Promise<string> => {
60+
console.log(`Running iteration ${iteration} after delay of ${delay}ms`);
61+
if (Date.now() > waitUntil) {
62+
return `success`;
63+
}
64+
throw new Error('custom error');
3265
};
33-
busywait(checkFn, {
34-
sleepTime: 500,
35-
maxChecks: 20,
36-
})
37-
.then((result: IBusyWaitResult<string>) => {
38-
console.log('finished after', result.iterations, 'iterations', 'with' +
39-
' result', result.result);
40-
});
66+
67+
(async () => {
68+
const result = await busywait(checkFn, {
69+
sleepTime: 100,
70+
jitter: 'none',
71+
multiplier: 2,
72+
})
73+
console.log(`Finished after ${result.backoff.time}ms (${result.backoff.iterations} iterations) with result ${result.result}`);
74+
})();
4175
```
76+
77+
Will result in:
78+
``` bash
79+
Running iteration 1 after delay of 0ms
80+
Running iteration 2 after delay of 100ms
81+
Running iteration 3 after delay of 200ms
82+
Running iteration 4 after delay of 400ms
83+
Running iteration 5 after delay of 800ms
84+
Running iteration 6 after delay of 1600ms
85+
Finished after 3111ms (6 iterations) with result success
86+
```
87+
88+
### Exponential backoff with full jitter
89+
90+
```typescript
91+
import { busywait } from 'busywait';
92+
93+
const waitUntil = Date.now() + 2500;
94+
95+
const checkFn = async (iteration: number, delay: number): Promise<string> => {
96+
console.log(`Running iteration ${iteration} after delay of ${delay}ms`);
97+
if (Date.now() > waitUntil) {
98+
return `success`;
99+
}
100+
throw new Error('custom error');
101+
};
102+
103+
(async () => {
104+
const result = await busywait(checkFn, {
105+
sleepTime: 100,
106+
jitter: 'full',
107+
multiplier: 2,
108+
waitFirst: true,
109+
})
110+
console.log(`Finished after ${result.backoff.time}ms (${result.backoff.iterations} iterations) with result ${result.result}`);
111+
})();
112+
```
113+
42114
Will result in:
43115
``` bash
44-
running iteration 1
45-
running iteration 2
46-
running iteration 3
47-
running iteration 4
48-
running iteration 5
49-
running iteration 6
50-
finished after 6 iterations with result success
116+
Running iteration 1 after delay of 78ms
117+
Running iteration 2 after delay of 154ms
118+
Running iteration 3 after delay of 228ms
119+
Running iteration 4 after delay of 605ms
120+
Running iteration 5 after delay of 136ms
121+
Running iteration 6 after delay of 1652ms
122+
Finished after 2863ms (6 iterations) with result success
51123
```
52124

53125
## Install
@@ -62,28 +134,32 @@ npm install busywait
62134
A function that takes a single optional argument, which is the current iteration number.
63135
The function can either:
64136
- return a non promised value (in which case, a failed check should throw an error)
65-
- return promised value (in which case, a failed check should return a rejection)
137+
- return promised value (in which case, a failed check should return a rejected promise)
66138

67139
#### options
68140

69141
##### mandatory
70142

71-
- `sleepTime` - Time in ms to wait between checks
72-
- `maxChecks` - The max number of checks to perform before failing
143+
- `sleepTime` - Time in ms to wait between checks. In the exponential mode, will be the base sleep time.
73144

74145
##### optional
75146

147+
- `multiplier` - The exponential multiplier. Set to 2 or higher to achieve exponential backoff (default: 1 - i.e. linear backoff)
148+
- `maxDelay` - The max delay value between checks in ms (default: infinity)
149+
- `maxChecks` - The max number of checks to perform before failing (default: infinity)
76150
- `waitFirst` - Should we wait the `sleepTime` before performing the first check (default: false)
151+
- `jitter` - ('none' | 'full') The [jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/) mode to use (default: none)
77152
- `failMsg` - Custom error message to reject the promise with
78153

79154
### Return value
80155

81156
Return value is a promise.
82-
- The promise will be resolved if the `checkFn` returned a valid value (resolved promise or did not throw an error) within a legal number of checks.
83-
- The promise will be rejected if the `checkFn` rejected ( or threw an error) `maxChecks` times.
157+
- The promise will be resolved if the `checkFn` was resolved within a legal number of checks.
158+
- The promise will be rejected if the `checkFn` rejected (or threw an error) `maxChecks` times.
84159

85160
Promise resolved value:
86-
- `iterations` - The number of iterations it took to finish
161+
- `backoff.iterations` - The number of iterations it took to finish
162+
- `backoff.time` - The number of time it took to finish
87163
- `result` - The resolved value of `checkFn`
88164

89165
## Contributing

0 commit comments

Comments
 (0)