Skip to content

Commit

Permalink
feat(client): onNonLazyError allows you to catch errors reported in…
Browse files Browse the repository at this point in the history
… non-lazy mode
  • Loading branch information
enisdenjo committed Dec 11, 2020
1 parent 05f1ef9 commit cd1e7df
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 2 deletions.
23 changes: 23 additions & 0 deletions docs/interfaces/_client_.clientoptions.md
Expand Up @@ -19,6 +19,7 @@ Configuration used for the GraphQL over WebSocket client.
* [keepAlive](_client_.clientoptions.md#keepalive)
* [lazy](_client_.clientoptions.md#lazy)
* [on](_client_.clientoptions.md#on)
* [onNonLazyError](_client_.clientoptions.md#onnonlazyerror)
* [retryAttempts](_client_.clientoptions.md#retryattempts)
* [retryWait](_client_.clientoptions.md#retrywait)
* [url](_client_.clientoptions.md#url)
Expand Down Expand Up @@ -91,6 +92,28 @@ to get the emitted event before other registered listeners.

___

### onNonLazyError

`Optional` **onNonLazyError**: undefined \| (errorOrCloseEvent: unknown) => void

Used ONLY when the client is in non-lazy mode (`lazy = false`). When
using this mode, the errors might have no sinks to report to. To avoid
swallowing errors, or having uncaught promises; consider using `onNonLazyError`,
which will be called when either:
- An unrecoverable error/close event occurs
- Silent retry attempts have been exceeded

After a client has errored out, it will NOT perform any automatic actions.

The argument can be a websocket `CloseEvent` or an `Error`. To avoid bundling
DOM types, you should derive and assert the correct type. When receiving:
- A `CloseEvent`: retry attempts have been exceeded or the specific
close event is labeled as fatal (read more in `retryAttempts`).
- An `Error`: some internal issue has occured, all internal errors are
fatal by nature.

___

### retryAttempts

`Optional` **retryAttempts**: undefined \| number
Expand Down
29 changes: 27 additions & 2 deletions src/client.ts
Expand Up @@ -77,6 +77,24 @@ export interface ClientOptions {
* @default true
*/
lazy?: boolean;
/**
* Used ONLY when the client is in non-lazy mode (`lazy = false`). When
* using this mode, the errors might have no sinks to report to. To avoid
* swallowing errors, or having uncaught promises; consider using `onNonLazyError`,
* which will be called when either:
* - An unrecoverable error/close event occurs
* - Silent retry attempts have been exceeded
*
* After a client has errored out, it will NOT perform any automatic actions.
*
* The argument can be a websocket `CloseEvent` or an `Error`. To avoid bundling
* DOM types, you should derive and assert the correct type. When receiving:
* - A `CloseEvent`: retry attempts have been exceeded or the specific
* close event is labeled as fatal (read more in `retryAttempts`).
* - An `Error`: some internal issue has occured, all internal errors are
* fatal by nature.
*/
onNonLazyError?: (errorOrCloseEvent: unknown) => void;
/**
* How long should the client wait before closing the socket after the last oparation has
* completed. This is meant to be used in combination with `lazy`. You might want to have
Expand Down Expand Up @@ -155,6 +173,7 @@ export function createClient(options: ClientOptions): Client {
url,
connectionParams,
lazy = true,
onNonLazyError,
keepAlive = 0,
retryAttempts = 5,
retryWait = async function randomisedExponentialBackoff(retries) {
Expand Down Expand Up @@ -523,8 +542,14 @@ export function createClient(options: ClientOptions): Client {
// cancelled, shouldnt try again
return;
} catch (errOrCloseEvent) {
// return if shouldnt try again
if (!shouldRetryConnectOrThrow(errOrCloseEvent)) return;
try {
// return and report if shouldnt try again
if (!shouldRetryConnectOrThrow(errOrCloseEvent))
return onNonLazyError?.(errOrCloseEvent);
} catch {
// report thrown error, no further retries
return onNonLazyError?.(errOrCloseEvent);
}
}
}
})();
Expand Down
18 changes: 18 additions & 0 deletions src/tests/client.ts
Expand Up @@ -645,6 +645,24 @@ describe('lazy', () => {
// but will close eventually
await server.waitForClientClose();
});

it('should report errors to the `onNonLazyError` callback', async (done) => {
const { url, ...server } = await startTServer();

createClient({
url,
lazy: false,
retryAttempts: 0,
onNonLazyError: (err) => {
expect((err as CloseEvent).code).toBe(1005);
done();
},
});

await server.waitForClient((client) => {
client.close();
});
});
});

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

0 comments on commit cd1e7df

Please sign in to comment.