Skip to content

Commit

Permalink
Add support for decorating and handling 429 errors with the saved obj…
Browse files Browse the repository at this point in the history
…ects client (#75664) (#75762)

* Add support for decorating 429 errors in the saved objects client

* Update the docs

Co-authored-by: Elastic Machine <[email protected]>

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
mikecote and elasticmachine authored Aug 24, 2020
1 parent 57e383d commit 2ec08f2
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) &gt; [createTooManyRequestsError](./kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md)

## SavedObjectsErrorHelpers.createTooManyRequestsError() method

<b>Signature:</b>

```typescript
static createTooManyRequestsError(type: string, id: string): DecoratedError;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| type | <code>string</code> | |
| id | <code>string</code> | |

<b>Returns:</b>

`DecoratedError`

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) &gt; [decorateTooManyRequestsError](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratetoomanyrequestserror.md)

## SavedObjectsErrorHelpers.decorateTooManyRequestsError() method

<b>Signature:</b>

```typescript
static decorateTooManyRequestsError(error: Error, reason?: string): DecoratedError;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| error | <code>Error</code> | |
| reason | <code>string</code> | |

<b>Returns:</b>

`DecoratedError`

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsErrorHelpers](./kibana-plugin-core-server.savedobjectserrorhelpers.md) &gt; [isTooManyRequestsError](./kibana-plugin-core-server.savedobjectserrorhelpers.istoomanyrequestserror.md)

## SavedObjectsErrorHelpers.isTooManyRequestsError() method

<b>Signature:</b>

```typescript
static isTooManyRequestsError(error: Error | DecoratedError): boolean;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| error | <code>Error &#124; DecoratedError</code> | |

<b>Returns:</b>

`boolean`

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export declare class SavedObjectsErrorHelpers
| [createConflictError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.createconflicterror.md) | <code>static</code> | |
| [createGenericNotFoundError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.creategenericnotfounderror.md) | <code>static</code> | |
| [createInvalidVersionError(versionInput)](./kibana-plugin-core-server.savedobjectserrorhelpers.createinvalidversionerror.md) | <code>static</code> | |
| [createTooManyRequestsError(type, id)](./kibana-plugin-core-server.savedobjectserrorhelpers.createtoomanyrequestserror.md) | <code>static</code> | |
| [createUnsupportedTypeError(type)](./kibana-plugin-core-server.savedobjectserrorhelpers.createunsupportedtypeerror.md) | <code>static</code> | |
| [decorateBadRequestError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratebadrequesterror.md) | <code>static</code> | |
| [decorateConflictError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorateconflicterror.md) | <code>static</code> | |
Expand All @@ -28,6 +29,7 @@ export declare class SavedObjectsErrorHelpers
| [decorateGeneralError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decorategeneralerror.md) | <code>static</code> | |
| [decorateNotAuthorizedError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratenotauthorizederror.md) | <code>static</code> | |
| [decorateRequestEntityTooLargeError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoraterequestentitytoolargeerror.md) | <code>static</code> | |
| [decorateTooManyRequestsError(error, reason)](./kibana-plugin-core-server.savedobjectserrorhelpers.decoratetoomanyrequestserror.md) | <code>static</code> | |
| [isBadRequestError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isbadrequesterror.md) | <code>static</code> | |
| [isConflictError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isconflicterror.md) | <code>static</code> | |
| [isEsCannotExecuteScriptError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isescannotexecutescripterror.md) | <code>static</code> | |
Expand All @@ -38,4 +40,5 @@ export declare class SavedObjectsErrorHelpers
| [isNotFoundError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isnotfounderror.md) | <code>static</code> | |
| [isRequestEntityTooLargeError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.isrequestentitytoolargeerror.md) | <code>static</code> | |
| [isSavedObjectsClientError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.issavedobjectsclienterror.md) | <code>static</code> | |
| [isTooManyRequestsError(error)](./kibana-plugin-core-server.savedobjectserrorhelpers.istoomanyrequestserror.md) | <code>static</code> | |

Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ describe('savedObjectsClient/decorateEsError', () => {
expect(SavedObjectsErrorHelpers.isConflictError(error)).toBe(true);
});

it('makes TooManyRequests a SavedObjectsClient/tooManyRequests error', () => {
const error = new esErrors.ResponseError(
elasticsearchClientMock.createApiResponse({ statusCode: 429 })
);
expect(SavedObjectsErrorHelpers.isTooManyRequestsError(error)).toBe(false);
expect(decorateEsError(error)).toBe(error);
expect(SavedObjectsErrorHelpers.isTooManyRequestsError(error)).toBe(true);
});

it('makes NotAuthorized a SavedObjectsClient/NotAuthorized error', () => {
const error = new esErrors.ResponseError(
elasticsearchClientMock.createApiResponse({ statusCode: 401 })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const responseErrors = {
isRequestEntityTooLarge: (statusCode: number) => statusCode === 413,
isNotFound: (statusCode: number) => statusCode === 404,
isBadRequest: (statusCode: number) => statusCode === 400,
isTooManyRequests: (statusCode: number) => statusCode === 429,
};
const { ConnectionError, NoLivingConnectionsError, TimeoutError } = esErrors;
const SCRIPT_CONTEXT_DISABLED_REGEX = /(?:cannot execute scripts using \[)([a-z]*)(?:\] context)/;
Expand Down Expand Up @@ -76,6 +77,10 @@ export function decorateEsError(error: EsErrors) {
return SavedObjectsErrorHelpers.createGenericNotFoundError();
}

if (responseErrors.isTooManyRequests(error.statusCode)) {
return SavedObjectsErrorHelpers.decorateTooManyRequestsError(error, reason);
}

if (responseErrors.isBadRequest(error.statusCode)) {
if (
SCRIPT_CONTEXT_DISABLED_REGEX.test(reason || '') ||
Expand Down
47 changes: 47 additions & 0 deletions src/core/server/saved_objects/service/lib/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,53 @@ describe('savedObjectsClient/errorTypes', () => {
});
});

describe('TooManyRequests error', () => {
describe('decorateTooManyRequestsError', () => {
it('returns original object', () => {
const error = new Error();
expect(SavedObjectsErrorHelpers.decorateTooManyRequestsError(error)).toBe(error);
});

it('makes the error identifiable as a TooManyRequests error', () => {
const error = new Error();
expect(SavedObjectsErrorHelpers.isTooManyRequestsError(error)).toBe(false);
SavedObjectsErrorHelpers.decorateTooManyRequestsError(error);
expect(SavedObjectsErrorHelpers.isTooManyRequestsError(error)).toBe(true);
});

it('adds boom properties', () => {
const error = SavedObjectsErrorHelpers.decorateTooManyRequestsError(new Error());
expect(error).toHaveProperty('isBoom', true);
});

describe('error.output', () => {
it('defaults to message of error', () => {
const error = SavedObjectsErrorHelpers.decorateTooManyRequestsError(new Error('foobar'));
expect(error.output.payload).toHaveProperty('message', 'foobar');
});

it('prefixes message with passed reason', () => {
const error = SavedObjectsErrorHelpers.decorateTooManyRequestsError(
new Error('foobar'),
'biz'
);
expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
});

it('sets statusCode to 429', () => {
const error = SavedObjectsErrorHelpers.decorateTooManyRequestsError(new Error('foo'));
expect(error.output).toHaveProperty('statusCode', 429);
});

it('preserves boom properties of input', () => {
const error = Boom.tooManyRequests();
SavedObjectsErrorHelpers.decorateTooManyRequestsError(error);
expect(error.output).toHaveProperty('statusCode', 429);
});
});
});
});

describe('EsCannotExecuteScript error', () => {
describe('decorateEsCannotExecuteScriptError', () => {
it('returns original object', () => {
Expand Down
14 changes: 14 additions & 0 deletions src/core/server/saved_objects/service/lib/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const CODE_REQUEST_ENTITY_TOO_LARGE = 'SavedObjectsClient/requestEntityTooLarge'
const CODE_NOT_FOUND = 'SavedObjectsClient/notFound';
// 409 - Conflict
const CODE_CONFLICT = 'SavedObjectsClient/conflict';
// 429 - Too Many Requests
const CODE_TOO_MANY_REQUESTS = 'SavedObjectsClient/tooManyRequests';
// 400 - Es Cannot Execute Script
const CODE_ES_CANNOT_EXECUTE_SCRIPT = 'SavedObjectsClient/esCannotExecuteScript';
// 503 - Es Unavailable
Expand Down Expand Up @@ -162,6 +164,18 @@ export class SavedObjectsErrorHelpers {
return isSavedObjectsClientError(error) && error[code] === CODE_CONFLICT;
}

public static decorateTooManyRequestsError(error: Error, reason?: string) {
return decorate(error, CODE_TOO_MANY_REQUESTS, 429, reason);
}

public static createTooManyRequestsError(type: string, id: string) {
return SavedObjectsErrorHelpers.decorateTooManyRequestsError(Boom.tooManyRequests());
}

public static isTooManyRequestsError(error: Error | DecoratedError) {
return isSavedObjectsClientError(error) && error[code] === CODE_TOO_MANY_REQUESTS;
}

public static decorateEsCannotExecuteScriptError(error: Error, reason?: string) {
return decorate(error, CODE_ES_CANNOT_EXECUTE_SCRIPT, 400, reason);
}
Expand Down
6 changes: 6 additions & 0 deletions src/core/server/server.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2220,6 +2220,8 @@ export class SavedObjectsErrorHelpers {
// (undocumented)
static createInvalidVersionError(versionInput?: string): DecoratedError;
// (undocumented)
static createTooManyRequestsError(type: string, id: string): DecoratedError;
// (undocumented)
static createUnsupportedTypeError(type: string): DecoratedError;
// (undocumented)
static decorateBadRequestError(error: Error, reason?: string): DecoratedError;
Expand All @@ -2238,6 +2240,8 @@ export class SavedObjectsErrorHelpers {
// (undocumented)
static decorateRequestEntityTooLargeError(error: Error, reason?: string): DecoratedError;
// (undocumented)
static decorateTooManyRequestsError(error: Error, reason?: string): DecoratedError;
// (undocumented)
static isBadRequestError(error: Error | DecoratedError): boolean;
// (undocumented)
static isConflictError(error: Error | DecoratedError): boolean;
Expand All @@ -2259,6 +2263,8 @@ export class SavedObjectsErrorHelpers {
//
// (undocumented)
static isSavedObjectsClientError(error: any): error is DecoratedError;
// (undocumented)
static isTooManyRequestsError(error: Error | DecoratedError): boolean;
}

// @public
Expand Down

0 comments on commit 2ec08f2

Please sign in to comment.