Skip to content

Commit

Permalink
fix(client): Shouldn't reconnect if all subscriptions complete while …
Browse files Browse the repository at this point in the history
…waiting for retry

Closes enisdenjo#163
  • Loading branch information
enisdenjo committed Apr 22, 2021
1 parent f24e9ba commit 2826c10
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 3 deletions.
14 changes: 11 additions & 3 deletions src/client.ts
Expand Up @@ -351,6 +351,13 @@ export function createClient(options: ClientOptions): Client {
(async () => {
if (retrying) {
await retryWait(retries);

// subscriptions might complete while waiting for retry
if (!locks) {
connecting = undefined;
return denied({ code: 1000, reason: 'All Subscriptions Gone' });
}

retries++;
}

Expand Down Expand Up @@ -431,9 +438,8 @@ export function createClient(options: ClientOptions): Client {
Promise.race([
// wait for
released.then(() => {
// decrement the subscription locks
if (!--locks) {
// and if no more are present, complete the connection
if (!locks) {
// and if no more locks are present, complete the connection
const complete = () => socket.close(1000, 'Normal Closure');
if (isFinite(keepAlive) && keepAlive > 0) {
// if the keepalive is set, allow for the specified calmdown time and
Expand Down Expand Up @@ -518,6 +524,7 @@ export function createClient(options: ClientOptions): Client {
let completed = false,
releaser = () => {
// for handling completions before connect
locks--;
completed = true;
};

Expand Down Expand Up @@ -566,6 +573,7 @@ export function createClient(options: ClientOptions): Client {
);

releaser = () => {
locks--;
if (!completed && socket.readyState === WebSocketImpl.OPEN)
// if not completed already and socket is open, send complete message to server on release
socket.send(
Expand Down
68 changes: 68 additions & 0 deletions src/tests/client.ts
Expand Up @@ -1074,6 +1074,74 @@ describe('reconnecting', () => {
// and all connections are gone
expect(server.getClients().length).toBe(0);
});

it('should not reconnect if the subscription completes while waiting for a retry', async () => {
const { url, ...server } = await startTServer();

let retryAttempt = () => {
/**/
};
const waitForRetryAttempt = () =>
new Promise<void>((resolve) => (retryAttempt = resolve));
let retry = () => {
/**/
};
const client = createClient({
url,
retryAttempts: 2,
retryWait: () => {
retryAttempt();
return new Promise((resolve) => (retry = resolve));
},
});

// case 1

// subscribe and wait for operation
let sub = tsubscribe(client, {
query: 'subscription { ping }',
});
await server.waitForOperation();

// close client then wait for retry attempt
await server.waitForClient((client) => {
client.close();
});
await waitForRetryAttempt();

// complete subscription while waiting
sub.dispose();

retry();

await server.waitForClient(() => {
fail("Client shouldn't have reconnected");
}, 20);

// case 2

// subscribe but close connection immediately (dont wait for operation)
sub = tsubscribe(client, {
query: 'subscription { ping }',
});
retry(); // this still counts as a retry, so retry
await server.waitForOperation();

// close client then wait for retry attempt
await server.waitForClient((client) => {
client.close();
});
await waitForRetryAttempt();

// complete subscription while waiting
sub.dispose();

retry();

await server.waitForClient(() => {
fail("Client shouldn't have reconnected");
}, 20);
});
});

describe('events', () => {
Expand Down

0 comments on commit 2826c10

Please sign in to comment.