Skip to content

Commit

Permalink
fix(server): Distribute server error to all clients even if one error…
Browse files Browse the repository at this point in the history
… listener throws (enisdenjo#56)

* fix: distribute error to all clients even if one error handler throws

* feat: rethrow first error and test

Co-authored-by: enisdenjo <badurinadenis@gmail.com>
  • Loading branch information
benjie and enisdenjo committed Nov 4, 2020
1 parent 0464a54 commit b96dbb9
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
15 changes: 13 additions & 2 deletions src/server.ts
Expand Up @@ -443,9 +443,20 @@ export function createServer(
}
webSocketServer.on('connection', handleConnection);
webSocketServer.on('error', (err) => {
// catch the first thrown error and re-throw it once all clients have been notified
let firstErr: Error | null = null;

// report server errors by erroring out all clients with the same error
for (const client of webSocketServer.clients) {
// report server errors by erroring out all clients with the same error
client.emit('error', err);
try {
client.emit('error', err);
} catch (err) {
firstErr = firstErr ?? err;
}
}

if (firstErr) {
throw firstErr;
}
});

Expand Down
35 changes: 35 additions & 0 deletions src/tests/server.ts
Expand Up @@ -452,6 +452,41 @@ it('should prefer the `onSubscribe` context value even if `context` option is se
);
});

it('should handle errors thrown from client error listeners', async () => {
const { server, url } = await startTServer();

const client = await createTClient(url);
client.ws.send(
stringifyMessage<MessageType.ConnectionInit>({
type: MessageType.ConnectionInit,
}),
);
await client.waitForMessage(({ data }) => {
expect(parseMessage(data).type).toBe(MessageType.ConnectionAck);
});

const surpriseErr1 = new Error('Well hello there!');
const surpriseErr2 = new Error('I wont be thrown!'); // first to throw stops emission
for (const client of server.webSocketServer.clients) {
client.on('error', () => {
throw surpriseErr1;
});
client.on('error', () => {
throw surpriseErr2;
});
}

expect(() => {
server.webSocketServer.emit('error', new Error('I am a nice error'));
}).toThrowError(surpriseErr1);

await client.waitForClose((event) => {
expect(event.code).toBe(1011);
expect(event.reason).toBe('I am a nice error');
expect(event.wasClean).toBeTruthy();
});
});

describe('Connect', () => {
it('should refuse connection and close socket if returning `false`', async () => {
const { url } = await startTServer({
Expand Down

0 comments on commit b96dbb9

Please sign in to comment.