Skip to content

Commit

Permalink
Standardize jitter implementation with Temporal.Duration
Browse files Browse the repository at this point in the history
  • Loading branch information
kachick committed Sep 11, 2024
1 parent 62c63ed commit e9ae955
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 29 deletions.
107 changes: 84 additions & 23 deletions __tests__/wait.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import {
wait,
calcExponentialBackoffAndJitter,
MIN_JITTER_MILLISECONDS,
MAX_JITTER_MILLISECONDS,
getInterval,
} from '../src/wait.ts';
import { wait, calcExponentialBackoffAndJitter, MIN_JITTER, MAX_JITTER, getInterval } from '../src/wait.ts';
import test from 'node:test';
import assert from 'node:assert';
import assert, { strictEqual } from 'node:assert';
import { Temporal } from 'temporal-polyfill';

test('wait 100 ms', async () => {
Expand All @@ -26,32 +20,99 @@ test('wait 100 ms', async () => {
test('interval will be like a cheap exponential backoff', () => {
const leastInterval = Temporal.Duration.from({ seconds: 100 });

assert(calcExponentialBackoffAndJitter(leastInterval, 1).total('milliseconds') >= (100000 + MIN_JITTER_MILLISECONDS));
assert(calcExponentialBackoffAndJitter(leastInterval, 1).total('milliseconds') < (100000 + MAX_JITTER_MILLISECONDS));
assert(calcExponentialBackoffAndJitter(leastInterval, 2).total('milliseconds') >= (200000 + MIN_JITTER_MILLISECONDS));
assert(calcExponentialBackoffAndJitter(leastInterval, 2).total('milliseconds') < (200000 + MAX_JITTER_MILLISECONDS));
assert(calcExponentialBackoffAndJitter(leastInterval, 3).total('milliseconds') >= (400000 + MIN_JITTER_MILLISECONDS));
assert(calcExponentialBackoffAndJitter(leastInterval, 3).total('milliseconds') < (400000 + MAX_JITTER_MILLISECONDS));
assert(calcExponentialBackoffAndJitter(leastInterval, 4).total('milliseconds') >= (800000 + MIN_JITTER_MILLISECONDS));
assert(calcExponentialBackoffAndJitter(leastInterval, 4).total('milliseconds') < (800000 + MAX_JITTER_MILLISECONDS));
assert(
calcExponentialBackoffAndJitter(leastInterval, 5).total('milliseconds') >= (1600000 + MIN_JITTER_MILLISECONDS),
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 1),
MIN_JITTER.add({ milliseconds: 100000 }),
) >= 0,
);
strictEqual(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 1),
MAX_JITTER.add({ milliseconds: 100000 }),
),
-1,
);

assert(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 2),
MIN_JITTER.add({ milliseconds: 200000 }),
) >= 0,
);
strictEqual(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 2),
MAX_JITTER.add({ milliseconds: 200000 }),
),
-1,
);

assert(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 3),
MIN_JITTER.add({ milliseconds: 400000 }),
) >= 0,
);
strictEqual(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 3),
MAX_JITTER.add({ milliseconds: 400000 }),
),
-1,
);

assert(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 4),
MIN_JITTER.add({ milliseconds: 800000 }),
) >= 0,
);
strictEqual(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 4),
MAX_JITTER.add({ milliseconds: 800000 }),
),
-1,
);

assert(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 5),
MIN_JITTER.add({ milliseconds: 1600000 }),
) >= 0,
);
strictEqual(
Temporal.Duration.compare(
calcExponentialBackoffAndJitter(leastInterval, 5),
MAX_JITTER.add({ milliseconds: 1600000 }),
),
-1,
);
assert(calcExponentialBackoffAndJitter(leastInterval, 5).total('milliseconds') < (1600000 + MAX_JITTER_MILLISECONDS));
});

test('getInterval returns different value with the given method', () => {
const leastInterval = Temporal.Duration.from({ seconds: 100 });

assert(
getInterval('exponential_backoff', leastInterval, 5).total('milliseconds') >= (1600000 + MIN_JITTER_MILLISECONDS),
Temporal.Duration.compare(
getInterval('exponential_backoff', leastInterval, 5),
MIN_JITTER.add({ milliseconds: 1600000 }),
) >= 0,
);
assert(
getInterval('exponential_backoff', leastInterval, 5).total('milliseconds') < (1600000 + MAX_JITTER_MILLISECONDS),
strictEqual(
Temporal.Duration.compare(
getInterval('exponential_backoff', leastInterval, 5),
MAX_JITTER.add({ milliseconds: 1600000 }),
),
-1,
);

assert.strictEqual(
Temporal.Duration.compare(getInterval('equal_intervals', leastInterval, 5), leastInterval),
strictEqual(
Temporal.Duration.compare(
getInterval('equal_intervals', leastInterval, 5),
leastInterval,
),
0,
);
});
10 changes: 7 additions & 3 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32570,10 +32570,14 @@ function getRandomInt(min, max) {
const flooredMin = Math.ceil(min);
return Math.floor(Math.random() * (Math.floor(max) - flooredMin) + flooredMin);
}
var MIN_JITTER_MILLISECONDS = 1e3;
var MAX_JITTER_MILLISECONDS = 7e3;
var MIN_JITTER = mr.Duration.from({
seconds: 1
});
var MAX_JITTER = mr.Duration.from({
seconds: 7
});
function calcExponentialBackoffAndJitter(leastInterval, attempts) {
const jitterMilliseconds = getRandomInt(MIN_JITTER_MILLISECONDS, MAX_JITTER_MILLISECONDS);
const jitterMilliseconds = getRandomInt(MIN_JITTER.total("milliseconds"), MAX_JITTER.total("milliseconds"));
return mr.Duration.from({
milliseconds: leastInterval.total("milliseconds") * 2 ** (attempts - 1) + jitterMilliseconds
});
Expand Down
10 changes: 7 additions & 3 deletions src/wait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@ function getRandomInt(min: number, max: number) {
return Math.floor((Math.random() * (Math.floor(max) - flooredMin)) + flooredMin);
}

export const MIN_JITTER_MILLISECONDS = 1000;
export const MAX_JITTER_MILLISECONDS = 7000;
export const MIN_JITTER = Temporal.Duration.from({
seconds: 1,
});
export const MAX_JITTER = Temporal.Duration.from({
seconds: 7,
});

export function calcExponentialBackoffAndJitter(
leastInterval: Temporal.Duration,
attempts: number,
): Temporal.Duration {
const jitterMilliseconds = getRandomInt(MIN_JITTER_MILLISECONDS, MAX_JITTER_MILLISECONDS);
const jitterMilliseconds = getRandomInt(MIN_JITTER.total('milliseconds'), MAX_JITTER.total('milliseconds'));
return Temporal.Duration.from({
milliseconds: (leastInterval.total('milliseconds') * (2 ** (attempts - 1))) + jitterMilliseconds,
});
Expand Down

0 comments on commit e9ae955

Please sign in to comment.