From 12fd286f7b905458c36d5b4212147cb856dbb692 Mon Sep 17 00:00:00 2001 From: Max Isom Date: Thu, 16 Jun 2022 14:16:32 -0500 Subject: [PATCH] Add request retries --- docs/classes/Seam.md | 6 ++-- docs/interfaces/SeamClientOptions.md | 6 ++-- docs/modules.md | 2 +- package.json | 2 ++ src/client.ts | 6 ++++ tests/retries.test.ts | 46 ++++++++++++++++++++++++++++ yarn.lock | 40 ++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 tests/retries.test.ts diff --git a/docs/classes/Seam.md b/docs/classes/Seam.md index 15cfe185..f2e2324d 100644 --- a/docs/classes/Seam.md +++ b/docs/classes/Seam.md @@ -47,7 +47,7 @@ Routes.constructor #### Defined in -[src/client.ts:39](https://github.com/seamapi/javascript/blob/main/src/client.ts#L39) +[src/client.ts:40](https://github.com/seamapi/javascript/blob/main/src/client.ts#L40) ## Properties @@ -99,7 +99,7 @@ ___ #### Defined in -[src/client.ts:37](https://github.com/seamapi/javascript/blob/main/src/client.ts#L37) +[src/client.ts:38](https://github.com/seamapi/javascript/blob/main/src/client.ts#L38) ___ @@ -239,4 +239,4 @@ Routes.makeRequest #### Defined in -[src/client.ts:70](https://github.com/seamapi/javascript/blob/main/src/client.ts#L70) +[src/client.ts:76](https://github.com/seamapi/javascript/blob/main/src/client.ts#L76) diff --git a/docs/interfaces/SeamClientOptions.md b/docs/interfaces/SeamClientOptions.md index 5bb19b98..52763214 100644 --- a/docs/interfaces/SeamClientOptions.md +++ b/docs/interfaces/SeamClientOptions.md @@ -18,7 +18,7 @@ #### Defined in -[src/client.ts:9](https://github.com/seamapi/javascript/blob/main/src/client.ts#L9) +[src/client.ts:10](https://github.com/seamapi/javascript/blob/main/src/client.ts#L10) ___ @@ -30,7 +30,7 @@ Seam Endpoint to use, defaults to https://connect.getseam.com #### Defined in -[src/client.ts:13](https://github.com/seamapi/javascript/blob/main/src/client.ts#L13) +[src/client.ts:14](https://github.com/seamapi/javascript/blob/main/src/client.ts#L14) ___ @@ -43,4 +43,4 @@ or undefined #### Defined in -[src/client.ts:18](https://github.com/seamapi/javascript/blob/main/src/client.ts#L18) +[src/client.ts:19](https://github.com/seamapi/javascript/blob/main/src/client.ts#L19) diff --git a/docs/modules.md b/docs/modules.md index 2caed19c..ac094201 100644 --- a/docs/modules.md +++ b/docs/modules.md @@ -306,4 +306,4 @@ ___ #### Defined in -[src/client.ts:21](https://github.com/seamapi/javascript/blob/main/src/client.ts#L21) +[src/client.ts:22](https://github.com/seamapi/javascript/blob/main/src/client.ts#L22) diff --git a/package.json b/package.json index 5960e5ae..ca184263 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ ], "dependencies": { "axios": "0.25.0", + "axios-retry": "3.2.5", "change-case": "4.1.2", "eventemitter3": "4.0.7", "lodash": "^4.17.21", @@ -76,6 +77,7 @@ "lint-staged": "12.3.1", "ms": "2.1.3", "nanoid": "3.2.0", + "nock": "13.2.7", "p-event": "4.2.0", "pgknexlove": "1.1.21", "pkg": "5.5.2", diff --git a/src/client.ts b/src/client.ts index 036f4bf0..3177c995 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,4 +1,5 @@ import axios, { AxiosInstance, AxiosRequestConfig } from "axios" +import axiosRetry from "axios-retry" import { SeamAPIError, SeamMalformedInputError } from "./lib/api-error" import { Routes } from "./routes" import { ErroredAPIResponse, SuccessfulAPIResponse } from "./types/globals" @@ -65,6 +66,11 @@ export class Seam extends Routes { ...(!workspaceId ? {} : { "Seam-Workspace": workspaceId }), }, }) + + axiosRetry(this.client, { + retries: 2, + retryDelay: axiosRetry.exponentialDelay, + }) } public async makeRequest( diff --git a/tests/retries.test.ts b/tests/retries.test.ts new file mode 100644 index 00000000..f4b6c1b9 --- /dev/null +++ b/tests/retries.test.ts @@ -0,0 +1,46 @@ +import test from "ava" +import { getServer } from "./fixtures/plugins/get-server-plugin" +import nock from "nock" + +test.serial("retries if network error", async (t) => { + const { client, url } = await getServer() + + const scope = nock(url, { allowUnmocked: true }) + .get("/health") + .once() + .replyWithError("Network error") + + const { ok } = await client.makeRequest({ url: "/health" }) + t.true(ok) + + t.true(scope.isDone()) +}) + +test.serial("retries failed request", async (t) => { + const { client, url } = await getServer() + + const scope = nock(url, { allowUnmocked: true }) + .get("/health") + .once() + .reply(500, "Internal Server Error") + + const { ok } = await client.makeRequest({ url: "/health" }) + t.true(ok) + + t.true(scope.isDone()) +}) + +test.serial("calls the endpoint a maximum of 3 times", async (t) => { + const { client, url } = await getServer() + + const scope = nock(url) + .get("/health") + .times(3) + .reply(500, "Internal Server Error") + + await t.throwsAsync(async () => { + await client.makeRequest({ url: "/health" }) + }) + + t.true(scope.isDone()) +}) diff --git a/yarn.lock b/yarn.lock index 86f371d7..3a3ae641 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,6 +42,13 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.2.tgz#3723cd5c8d8773eef96ce57ea1d9b7faaccd12ac" integrity sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw== +"@babel/runtime@^7.15.4": + version "7.18.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" + integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/types@7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" @@ -1033,6 +1040,14 @@ ava@4.0.1: write-file-atomic "^3.0.3" yargs "^17.3.1" +axios-retry@3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.2.5.tgz#64952992837c7d9a12eec156a2694a7945f60895" + integrity sha512-a8umkKbfIkTiYJQLx3v3TzKM85TGKB8ZQYz4zwykt2fpO64TsRlUhjaPaAb3fqMWCXFm2YhWcd8V5FHDKO9bSA== + dependencies: + "@babel/runtime" "^7.15.4" + is-retry-allowed "^2.2.0" + axios@0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a" @@ -2982,6 +2997,11 @@ is-promise@^4.0.0: resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== +is-retry-allowed@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" + integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== + is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -3830,6 +3850,16 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" +nock@13.2.7: + version "13.2.7" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.2.7.tgz#c93933b61df42f4f4b3a07fde946a4e209c0c168" + integrity sha512-R6NUw7RIPtKwgK7jskuKoEi4VFMqIHtV2Uu9K/Uegc4TA5cqe+oNMYslZcUmnVNQCTG6wcSqUBaGTDd7sq5srg== + dependencies: + debug "^4.1.0" + json-stringify-safe "^5.0.1" + lodash "^4.17.21" + propagate "^2.0.0" + node-abi@^2.21.0: version "2.30.1" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.30.1.tgz#c437d4b1fe0e285aaf290d45b45d4d7afedac4cf" @@ -4737,6 +4767,11 @@ promzard@^0.3.0: dependencies: read "1" +propagate@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" + integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== + proper-lockfile@4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" @@ -4930,6 +4965,11 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + registry-auth-token@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250"