From eb0eb267eef4fa4f8f62464d4318db4420d00482 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Thu, 15 May 2025 10:58:53 +0200 Subject: [PATCH 1/2] fix: improved retry logic, improve retry logging --- packages/node-sdk/src/cache.ts | 3 ++- packages/node-sdk/src/client.ts | 11 ++++++----- packages/node-sdk/src/fetch-http-client.ts | 5 ++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/node-sdk/src/cache.ts b/packages/node-sdk/src/cache.ts index 59800b23..025ee78c 100644 --- a/packages/node-sdk/src/cache.ts +++ b/packages/node-sdk/src/cache.ts @@ -34,6 +34,8 @@ export default function cache( if (newValue === undefined) { return; } + logger?.info("refreshed features"); + cachedValue = newValue; lastUpdate = Date.now(); @@ -63,7 +65,6 @@ export default function cache( refreshPromise = update(); } await refreshPromise; - logger?.info("refreshed cached features"); return get(); }; diff --git a/packages/node-sdk/src/client.ts b/packages/node-sdk/src/client.ts index a72b5488..6597740a 100644 --- a/packages/node-sdk/src/client.ts +++ b/packages/node-sdk/src/client.ts @@ -675,7 +675,7 @@ export class BucketClient { if (!response.ok || !isObject(response.body) || !response.body.success) { this.logger.warn( `invalid response received from server for "${url}"`, - response, + JSON.stringify(response), ); return false; } @@ -713,15 +713,16 @@ export class BucketClient { !isObject(response.body) || !response.body.success ) { - this.logger.warn( - `invalid response received from server for "${url}"`, - response, + throw new Error( + `invalid response received from server for "${url}": ${JSON.stringify(response.body)}`, ); - return undefined; } const { success: _, ...result } = response.body; return result as TResponse; }, + () => { + this.logger.warn("failed to fetch features, will retry"); + }, retries, 1000, 10000, diff --git a/packages/node-sdk/src/fetch-http-client.ts b/packages/node-sdk/src/fetch-http-client.ts index ac6642bc..b7da9cfd 100644 --- a/packages/node-sdk/src/fetch-http-client.ts +++ b/packages/node-sdk/src/fetch-http-client.ts @@ -67,6 +67,7 @@ const fetchClient: HttpClient = { */ export async function withRetry( fn: () => Promise, + onFailedTry: () => void, maxRetries: number, baseDelay: number, maxDelay: number, @@ -83,13 +84,15 @@ export async function withRetry( break; } + onFailedTry(); + // Calculate exponential backoff with jitter const delay = Math.min( maxDelay, baseDelay * Math.pow(2, attempt) * (0.8 + Math.random() * 0.4), ); - await new Promise((resolve) => setTimeout(resolve, delay).unref()); + await new Promise((resolve) => setTimeout(resolve, delay)); } } From 392a24d4c5432db9ed754985bd1cbe208add55c6 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Thu, 15 May 2025 11:30:04 +0200 Subject: [PATCH 2/2] update tests --- packages/node-sdk/test/client.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/node-sdk/test/client.test.ts b/packages/node-sdk/test/client.test.ts index 36873fcb..9dad7671 100644 --- a/packages/node-sdk/test/client.test.ts +++ b/packages/node-sdk/test/client.test.ts @@ -88,7 +88,7 @@ const validOptions: ClientOptions = { featuresFetchRetries: 2, batchOptions: { maxSize: 99, - intervalMs: 100, + intervalMs: 10001, flushOnExit: false, }, offline: false, @@ -270,7 +270,7 @@ describe("BucketClient", () => { expect(client["_config"].headers).toEqual(expectedHeaders); expect(client["batchBuffer"]).toMatchObject({ maxSize: 99, - intervalMs: 100, + intervalMs: 10001, }); expect(client["_config"].fallbackFeatures).toEqual({ @@ -630,7 +630,7 @@ describe("BucketClient", () => { expect(logger.warn).toHaveBeenCalledWith( expect.stringMatching("invalid response received from server for"), - response, + JSON.stringify(response), ); }); @@ -722,7 +722,7 @@ describe("BucketClient", () => { expect(logger.warn).toHaveBeenCalledWith( expect.stringMatching("invalid response received from server for"), - response, + JSON.stringify(response), ); }); @@ -859,7 +859,7 @@ describe("BucketClient", () => { expect(logger.warn).toHaveBeenCalledWith( expect.stringMatching("invalid response received from server for "), - response, + JSON.stringify(response), ); });