Allow passing in a signal to abort a cluster client request (#37563)

* Allow passing in a signal to abort an Elasticsearch request using the cluster client

* Go back to using promises (which still return abort method) and update test

* Update docs

* Explicitly return Promise<any> instead of {}
This commit is contained in:
Lukas Olson 2019-06-12 15:43:22 -07:00 committed by GitHub
parent 4785301ed9
commit 9e472e66fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 2 deletions

View file

@ -16,5 +16,6 @@ export interface CallAPIOptions
| Property | Type | Description |
| --- | --- | --- |
| [signal](./kibana-plugin-server.callapioptions.signal.md) | <code>AbortSignal</code> | A signal object that allows you to abort the request via an AbortController object. |
| [wrap401Errors](./kibana-plugin-server.callapioptions.wrap401errors.md) | <code>boolean</code> | Indicates whether <code>401 Unauthorized</code> errors returned from the Elasticsearch API should be wrapped into <code>Boom</code> error instances with properly set <code>WWW-Authenticate</code> header that could have been returned by the API itself. If API didn't specify that then <code>Basic realm=&quot;Authorization Required&quot;</code> is used as <code>WWW-Authenticate</code>. |

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [CallAPIOptions](./kibana-plugin-server.callapioptions.md) &gt; [signal](./kibana-plugin-server.callapioptions.signal.md)
## CallAPIOptions.signal property
A signal object that allows you to abort the request via an AbortController object.
<b>Signature:</b>
```typescript
signal?: AbortSignal;
```

View file

@ -165,6 +165,25 @@ describe('#callAsInternalUser', () => {
).rejects.toStrictEqual(mockAuthenticationError);
});
test('aborts the request and rejects if a signal is provided and aborted', async () => {
const controller = new AbortController();
// The ES client returns a promise with an additional `abort` method to abort the request
const mockValue: any = Promise.resolve();
mockValue.abort = jest.fn();
mockEsClientInstance.ping.mockReturnValue(mockValue);
const promise = clusterClient.callAsInternalUser('ping', undefined, {
wrap401Errors: false,
signal: controller.signal,
});
controller.abort();
expect(mockValue.abort).toHaveBeenCalled();
await expect(promise).rejects.toThrowErrorMatchingInlineSnapshot(`"Request was aborted"`);
});
test('does not override WWW-Authenticate if returned by Elasticsearch', async () => {
const mockAuthenticationError = new (errors.AuthenticationException as any)(
'Authentication Exception',

View file

@ -42,6 +42,10 @@ export interface CallAPIOptions {
* then `Basic realm="Authorization Required"` is used as `WWW-Authenticate`.
*/
wrap401Errors: boolean;
/**
* A signal object that allows you to abort the request via an AbortController object.
*/
signal?: AbortSignal;
}
/**
@ -57,7 +61,7 @@ async function callAPI(
endpoint: string,
clientParams: Record<string, unknown> = {},
options: CallAPIOptions = { wrap401Errors: true }
) {
): Promise<any> {
const clientPath = endpoint.split('.');
const api: any = get(client, clientPath);
if (!api) {
@ -66,7 +70,16 @@ async function callAPI(
const apiContext = clientPath.length === 1 ? client : get(client, clientPath.slice(0, -1));
try {
return await api.call(apiContext, clientParams);
return await new Promise((resolve, reject) => {
const request = api.call(apiContext, clientParams);
if (options.signal) {
options.signal.addEventListener('abort', () => {
request.abort();
reject(new Error('Request was aborted'));
});
}
return request.then(resolve, reject);
});
} catch (err) {
if (!options.wrap401Errors || err.statusCode !== 401) {
throw err;

View file

@ -43,6 +43,7 @@ export function bootstrap({ configs, cliArgs, applyConfigOverrides, features, }:
// @public
export interface CallAPIOptions {
signal?: AbortSignal;
wrap401Errors: boolean;
}

View file

@ -206,6 +206,7 @@ export interface DeprecationAPIResponse {
export interface CallClusterOptions {
wrap401Errors?: boolean;
signal?: AbortSignal;
}
export interface CallClusterWithRequest {