diff --git a/lib/client_factory.ts b/lib/client_factory.ts index f8588c33c..8bbc688ef 100644 --- a/lib/client_factory.ts +++ b/lib/client_factory.ts @@ -21,12 +21,13 @@ import { extractEventProcessor } from "./event_processor/event_processor_factory import { extractOdpManager } from "./odp/odp_manager_factory"; import { extractVuidManager } from "./vuid/vuid_manager_factory"; import { RequestHandler } from "./utils/http_request_handler/http"; -import { CLIENT_VERSION, DEFAULT_CMAB_CACHE_SIZE, DEFAULT_CMAB_CACHE_TIMEOUT, JAVASCRIPT_CLIENT_ENGINE } from "./utils/enums"; +import { CLIENT_VERSION, DEFAULT_CMAB_BACKOFF_MS, DEFAULT_CMAB_CACHE_SIZE, DEFAULT_CMAB_CACHE_TIMEOUT_MS, DEFAULT_CMAB_RETRIES, JAVASCRIPT_CLIENT_ENGINE } from "./utils/enums"; import Optimizely from "./optimizely"; import { DefaultCmabClient } from "./core/decision_service/cmab/cmab_client"; import { CmabCacheValue, DefaultCmabService } from "./core/decision_service/cmab/cmab_service"; import { InMemoryLruCache } from "./utils/cache/in_memory_lru_cache"; import { transformCache, CacheWithRemove } from "./utils/cache/cache"; +import { ConstantBackoff } from "./utils/repeater/repeater"; export type OptimizelyFactoryConfig = Config & { requestHandler: RequestHandler; @@ -53,13 +54,17 @@ export const getOptimizelyInstance = (config: OptimizelyFactoryConfig): Optimize const cmabClient = new DefaultCmabClient({ requestHandler, + retryConfig: { + maxRetries: DEFAULT_CMAB_RETRIES, + backoffProvider: () => new ConstantBackoff(DEFAULT_CMAB_BACKOFF_MS), + } }); const cmabCache: CacheWithRemove = config.cmab?.cache ? transformCache(config.cmab.cache, (value) => JSON.parse(value), (value) => JSON.stringify(value)) : (() => { const cacheSize = config.cmab?.cacheSize || DEFAULT_CMAB_CACHE_SIZE; - const cacheTtl = config.cmab?.cacheTtl || DEFAULT_CMAB_CACHE_TIMEOUT; + const cacheTtl = config.cmab?.cacheTtl || DEFAULT_CMAB_CACHE_TIMEOUT_MS; return new InMemoryLruCache(cacheSize, cacheTtl); })(); diff --git a/lib/odp/odp_manager_factory.ts b/lib/odp/odp_manager_factory.ts index 9fd689964..45c79e591 100644 --- a/lib/odp/odp_manager_factory.ts +++ b/lib/odp/odp_manager_factory.ts @@ -26,7 +26,7 @@ import { DefaultOdpSegmentApiManager } from "./segment_manager/odp_segment_api_m import { DefaultOdpSegmentManager, OdpSegmentManager } from "./segment_manager/odp_segment_manager"; import { UserAgentParser } from "./ua_parser/user_agent_parser"; -export const DEFAULT_CACHE_SIZE = 1000; +export const DEFAULT_CACHE_SIZE = 10_000; export const DEFAULT_CACHE_TIMEOUT = 600_000; export const DEFAULT_EVENT_BATCH_SIZE = 100; diff --git a/lib/utils/enums/index.ts b/lib/utils/enums/index.ts index 99c254e5e..fc95f2ef2 100644 --- a/lib/utils/enums/index.ts +++ b/lib/utils/enums/index.ts @@ -102,5 +102,7 @@ export const DECISION_MESSAGES = { */ export const REQUEST_TIMEOUT_MS = 60 * 1000; // 1 minute -export const DEFAULT_CMAB_CACHE_TIMEOUT = 30 * 60 * 1000; // 30 minutes -export const DEFAULT_CMAB_CACHE_SIZE = 1000; +export const DEFAULT_CMAB_CACHE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes +export const DEFAULT_CMAB_CACHE_SIZE = 10_000; +export const DEFAULT_CMAB_RETRIES = 1; +export const DEFAULT_CMAB_BACKOFF_MS = 100; // 100 milliseconds diff --git a/lib/utils/repeater/repeater.spec.ts b/lib/utils/repeater/repeater.spec.ts index e92594556..b992e0e85 100644 --- a/lib/utils/repeater/repeater.spec.ts +++ b/lib/utils/repeater/repeater.spec.ts @@ -1,5 +1,5 @@ /** - * Copyright 2024, Optimizely + * Copyright 2024-2025, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ import { expect, vi, it, beforeEach, afterEach, describe } from 'vitest'; -import { ExponentialBackoff, IntervalRepeater } from './repeater'; +import { ConstantBackoff, ExponentialBackoff, IntervalRepeater } from './repeater'; import { advanceTimersByTime } from '../../tests/testUtils'; import { resolvablePromise } from '../promise/resolvablePromise'; @@ -88,6 +88,23 @@ describe("ExponentialBackoff", () => { }); +describe("ConstantBackoff", () => { + it("should always return the same backoff time", () => { + const constantBackoff = new ConstantBackoff(3000); + for(let i = 0; i < 5; i++) { + const time = constantBackoff.backoff(); + expect(time).toEqual(3000); + } + + // Reset to verify it still returns the same value + constantBackoff.reset(); + for(let i = 0; i < 5; i++) { + const time = constantBackoff.backoff(); + expect(time).toEqual(3000); + } + }); +}); + describe("IntervalRepeater", () => { beforeEach(() => { vi.useFakeTimers(); diff --git a/lib/utils/repeater/repeater.ts b/lib/utils/repeater/repeater.ts index 9f307ab95..829702729 100644 --- a/lib/utils/repeater/repeater.ts +++ b/lib/utils/repeater/repeater.ts @@ -1,5 +1,5 @@ /** - * Copyright 2024, Optimizely + * Copyright 2024-2025, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,6 +63,21 @@ export class ExponentialBackoff implements BackoffController { } } +export class ConstantBackoff implements BackoffController { + private value: number; + + constructor(value: number) { + this.value = value; + } + + backoff(): number { + return this.value; + } + + reset(): void { + } +} + // IntervalRepeater is a Repeater that invokes the task at a fixed interval // after the completion of the previous task invocation. If a backoff controller // is provided, the repeater will use the backoff controller to determine the