Skip to content

Commit

Permalink
Add calculateRetryDelayFactor helper function
Browse files Browse the repository at this point in the history
This is used to calculate the exponentially increasing delay. The
function is used to calculate the reconnection delay - but does not keep
track of the current reconnection attempt. Keeping track of the current
reconnection attempt is reserved for the next few commits.
  • Loading branch information
justuswilhelm committed Apr 19, 2024
1 parent 0bb979b commit 21749aa
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
29 changes: 29 additions & 0 deletions __tests__/index/retryConnectionDelay.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// File Dependencies
import Sarus from "../../src/index";
import { WS } from "jest-websocket-mock";
import { calculateRetryDelayFactor } from "../../src/index";
import type { ExponentialBackoffParams } from "../../src/index";

const url = "ws://localhost:1234";

Expand Down Expand Up @@ -61,3 +63,30 @@ describe("retry connection delay", () => {
});
});
});

describe("Exponential backoff delay", () => {
it("will never be more than 8000 ms with rate set to 2", () => {
// The initial delay shall be 1 s
const initialDelay = 1000;
const exponentialBackoffParams: ExponentialBackoffParams = {
backoffRate: 2,
// We put the ceiling at exactly 8000 ms
backoffLimit: 8000,
};
expect(
calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 0),
).toBe(1000);
expect(
calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 1),
).toBe(2000);
expect(
calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 2),
).toBe(4000);
expect(
calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 3),
).toBe(8000);
expect(
calculateRetryDelayFactor(exponentialBackoffParams, initialDelay, 4),
).toBe(8000);
});
});
37 changes: 34 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,29 @@ export interface ExponentialBackoffParams {
backoffLimit: number;
}

/*
* Calculate the exponential backoff delay for a given number of connection
* attempts.
* @param {ExponentialBackoffParams} params - configuration parameters for
* exponential backoff.
* @param {number} initialDelay - the initial delay before any backoff is
* applied
* @param {number} connectionAttempts - the number of connection attempts
* that have previously failed, excluding the original connection attempt that
* succeeded
* @returns {void} - set does not return
*/
export function calculateRetryDelayFactor(
params: ExponentialBackoffParams,
initialDelay: number,
connectionAttempts: number,
): number {
return Math.min(
initialDelay * Math.pow(params.backoffRate, connectionAttempts),
params.backoffLimit,
);
}

export interface SarusClassParams {
url: string;
binaryType?: BinaryType;
Expand Down Expand Up @@ -363,12 +386,20 @@ export default class Sarus {
}

/**
* Reconnects the WebSocket client based on the retryConnectionDelay setting.
* Reconnects the WebSocket client based on the retryConnectionDelay and
* ExponentialBackoffParam setting.
*/
reconnect() {
const self = this;
const { retryConnectionDelay } = self;
setTimeout(self.connect, retryConnectionDelay);
const { retryConnectionDelay, exponentialBackoff } = self;

// If no exponential backoff is enabled, retryConnectionDelay will
// be scaled by a factor of 1 and it will stay the original value.
const delay = exponentialBackoff
? calculateRetryDelayFactor(exponentialBackoff, retryConnectionDelay, 0)
: retryConnectionDelay;

setTimeout(self.connect, delay);
}

/**
Expand Down

0 comments on commit 21749aa

Please sign in to comment.