feat: retry network errors and rate limits
This commit is contained in:
52
src/index.ts
52
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 = {
|
||||
|
||||
Reference in New Issue
Block a user