From 0798b40e325101baf5699c1eb02f782d56a8dd1c Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Sun, 13 Apr 2025 21:28:46 +0400 Subject: [PATCH 1/4] feat: retry network errors and rate limits --- src/index.ts | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 64d5965..b0ab59d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import { Configuration, DefaultApi as InfisicalApi } from "./infisicalapi_client import { DefaultApiApiV1DynamicSecretsLeasesPostRequest } from "./infisicalapi_client"; import SecretsClient from "./custom/secrets"; import AuthClient from "./custom/auth"; -import { RawAxiosRequestConfig } from "axios"; +import axios, { AxiosError, AxiosInstance, RawAxiosRequestConfig } from "axios"; import DynamicSecretsClient from "./custom/dynamic-secrets"; import * as ApiClient from "./infisicalapi_client"; @@ -10,6 +10,12 @@ import EnvironmentsClient from "./custom/environments"; import ProjectsClient from "./custom/projects"; import FoldersClient from "./custom/folders"; +declare module "axios" { + interface AxiosRequestConfig { + _retryCount?: number; + } +} + const buildRestClient = (apiClient: InfisicalApi, requestOptions?: RawAxiosRequestConfig) => { return { // Add more as we go @@ -18,6 +24,40 @@ const buildRestClient = (apiClient: InfisicalApi, requestOptions?: RawAxiosReque }; }; +const setupAxiosRetry = () => { + const axiosInstance = axios.create(); + const maxRetries = 4; + + const initialRetryDelay = 1000; + + const backoffFactor = 2; + + axiosInstance.interceptors.response.use(null, (error: AxiosError) => { + const config = error?.config; + + if (!config) { + return Promise.reject(error); + } + + if (!config._retryCount) config._retryCount = 0; + + // handle rate limits and network errors + if ((error.response?.status === 429 || error.response?.status === undefined) && config && config._retryCount! < maxRetries) { + config._retryCount!++; + const exponentialDelay = Math.min(initialRetryDelay * Math.pow(backoffFactor, config._retryCount! - 1)); + + return new Promise(async resolve => { + await new Promise(resolve => setTimeout(resolve, exponentialDelay)); + resolve(axiosInstance(config)); + }); + } + + return Promise.reject(error); + }); + + return axiosInstance; +}; + // We need to do bind(this) because the authenticate method is a private method, and usually you can't call private methods from outside the class. type InfisicalSDKOptions = { siteUrl?: string; @@ -34,14 +74,18 @@ class InfisicalSDK { #foldersClient: FoldersClient; #authClient: AuthClient; #basePath: string; + axiosInstance: AxiosInstance; constructor(options?: InfisicalSDKOptions) { this.#basePath = options?.siteUrl || "https://app.infisical.com"; + this.axiosInstance = setupAxiosRetry(); this.#apiInstance = new InfisicalApi( new Configuration({ basePath: this.#basePath - }) + }), + undefined, + this.axiosInstance ); this.#authClient = new AuthClient(this.authenticate.bind(this), this.#apiInstance); @@ -58,7 +102,9 @@ class InfisicalSDK { new Configuration({ basePath: this.#basePath, accessToken - }) + }), + undefined, + this.axiosInstance ); this.#requestOptions = { From 48ccf7a73a4374373b2595241851f8d07848c0ed Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Sun, 13 Apr 2025 21:33:18 +0400 Subject: [PATCH 2/4] requested changes --- src/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index b0ab59d..0aa40a7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,9 +46,10 @@ const setupAxiosRetry = () => { config._retryCount!++; const exponentialDelay = Math.min(initialRetryDelay * Math.pow(backoffFactor, config._retryCount! - 1)); - return new Promise(async resolve => { - await new Promise(resolve => setTimeout(resolve, exponentialDelay)); - resolve(axiosInstance(config)); + return new Promise(resolve => { + setTimeout(() => { + resolve(axiosInstance(config)); + }, exponentialDelay); }); } From 71bc65c293f28c4db1da53200634400c4207d374 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Wed, 16 Apr 2025 23:54:14 +0400 Subject: [PATCH 3/4] Update index.ts --- src/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0aa40a7..78df3ad 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,7 +29,6 @@ const setupAxiosRetry = () => { const maxRetries = 4; const initialRetryDelay = 1000; - const backoffFactor = 2; axiosInstance.interceptors.response.use(null, (error: AxiosError) => { @@ -44,7 +43,9 @@ const setupAxiosRetry = () => { // handle rate limits and network errors if ((error.response?.status === 429 || error.response?.status === undefined) && config && config._retryCount! < maxRetries) { config._retryCount!++; - const exponentialDelay = Math.min(initialRetryDelay * Math.pow(backoffFactor, config._retryCount! - 1)); + const baseDelay = initialRetryDelay * Math.pow(backoffFactor, config._retryCount! - 1); + const jitter = baseDelay * 0.2; // 20% +/- jitter + const exponentialDelay = Math.min(baseDelay + (Math.random() * 2 - 1) * jitter); return new Promise(resolve => { setTimeout(() => { From 64fde98904e008015f11533ce823825d5ebb2bef Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 17 Apr 2025 00:19:39 +0400 Subject: [PATCH 4/4] Update index.ts --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 78df3ad..6ea6430 100644 --- a/src/index.ts +++ b/src/index.ts @@ -45,7 +45,7 @@ const setupAxiosRetry = () => { config._retryCount!++; const baseDelay = initialRetryDelay * Math.pow(backoffFactor, config._retryCount! - 1); const jitter = baseDelay * 0.2; // 20% +/- jitter - const exponentialDelay = Math.min(baseDelay + (Math.random() * 2 - 1) * jitter); + const exponentialDelay = baseDelay + (Math.random() * 2 - 1) * jitter; return new Promise(resolve => { setTimeout(() => {