Skip to content
This repository was archived by the owner on Nov 9, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ module.exports = {
// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 78.94,
branches: 86.95,
functions: 100,
lines: 96.27,
statements: 96.27,
lines: 97.51,
statements: 97.51,
},
},

Expand Down
17 changes: 15 additions & 2 deletions src/createStreamMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface IdMapValue {
res: PendingJsonRpcResponse<unknown>;
next: JsonRpcEngineNextCallback;
end: JsonRpcEngineEndCallback;
retryCount?: number;
}

interface IdMap {
Expand Down Expand Up @@ -129,8 +130,20 @@ export default function createStreamMiddleware(options: Options = {}) {
* Retry pending requests.
*/
function retryStuckRequests() {
Object.values(idMap).forEach(({ req }) => {
// TODO: limiting retries could be implemented here
Object.values(idMap).forEach(({ req, retryCount = 0 }) => {
// Avoid retrying requests without an id - they cannot have matching responses so retry logic doesn't apply
// Check for retry count below ensure that a request is not retried more than 3 times
if (!req.id) {
return;
}

if (retryCount >= 3) {
throw new Error(
`StreamMiddleware - Retry limit exceeded for request id "${req.id}"`,
);
}

idMap[req.id].retryCount = retryCount + 1;
sendToStream(req);
});
}
Expand Down
72 changes: 66 additions & 6 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,20 @@ describe('middleware and engine to stream', () => {

const RECONNECTED = 'CONNECTED';
describe('retry logic in middleware connected to a port', () => {
it('retries requests on reconnect message', async () => {
let engineA: JsonRpcEngine | undefined;
let messages: any[] = [];
let messageConsumer: any;
beforeEach(() => {
// create guest
const engineA = new JsonRpcEngine();
engineA = new JsonRpcEngine();
const jsonRpcConnection = createStreamMiddleware({
retryOnMessage: RECONNECTED,
});
engineA.push(jsonRpcConnection.middleware);

// create port
let messageConsumer = noop;
const messages: any[] = [];
messageConsumer = noop;
messages = [];
const extensionPort = {
onMessage: {
addListener: (cb: any) => {
Expand All @@ -143,15 +146,17 @@ describe('retry logic in middleware connected to a port', () => {
clientSideStream
.pipe(connectionStream as unknown as Duplex)
.pipe(clientSideStream);
});

it('retries requests on reconnect message', async () => {
// request and expected result
const req1 = { id: 1, jsonrpc, method: 'test' };
const req2 = { id: 2, jsonrpc, method: 'test' };
const res = { id: 1, jsonrpc, result: 'test' };

// Initially sent once
const responsePromise1 = engineA.handle(req1);
engineA.handle(req2);
const responsePromise1 = engineA?.handle(req1);
engineA?.handle(req2);
await artificialDelay();

expect(messages).toHaveLength(2);
Expand Down Expand Up @@ -179,4 +184,59 @@ describe('retry logic in middleware connected to a port', () => {

expect(messages).toHaveLength(5);
});

it('throw error when requests are retried more than 3 times', async () => {
// request and expected result
const req = { id: 1, jsonrpc, method: 'test' };

// Initially sent once, message count at 1
engineA?.handle(req);
await artificialDelay();
expect(messages).toHaveLength(1);

// Reconnected, gets sent again message count increased to 2
messageConsumer({
method: RECONNECTED,
});
await artificialDelay();
expect(messages).toHaveLength(2);

// Reconnected, gets sent again message count increased to 3
messageConsumer({
method: RECONNECTED,
});
await artificialDelay();
expect(messages).toHaveLength(3);

// Reconnected, gets sent again message count increased to 4
messageConsumer({
method: RECONNECTED,
});
await artificialDelay();
expect(messages).toHaveLength(4);

// Reconnected, error is thrrown when trying to resend request more that 3 times
expect(() => {
messageConsumer({
method: RECONNECTED,
});
}).toThrow('StreamMiddleware - Retry limit exceeded for request id');
});

it('does not retry if the request has no id', async () => {
// request and expected result
const req = { id: undefined, jsonrpc, method: 'test' };

// Initially sent once, message count at 1
engineA?.handle(req);
await artificialDelay();
expect(messages).toHaveLength(1);

// Reconnected, but request is not re-submitted
messageConsumer({
method: RECONNECTED,
});
await artificialDelay();
expect(messages).toHaveLength(1);
});
});