From d26609433d8d8bb18cb3350323ab3b7c8e33ae1e Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Mon, 29 Jul 2024 12:17:02 -0300 Subject: [PATCH 01/11] FFM-11788 Start adding max stream retry config --- src/index.ts | 3 ++- src/stream.ts | 9 ++++++--- src/types.ts | 7 +++++++ src/utils.ts | 3 ++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index 944b787..dcd2705 100644 --- a/src/index.ts +++ b/src/index.ts @@ -543,7 +543,8 @@ const initialize = (apiKey: string, target: Target, options?: Options): Result = } else if (event.domain === 'target-segment') { handleSegmentEvent(event) } - } + }, + configurations.maxStreamingRetries ) eventSource.start() } diff --git a/src/stream.ts b/src/stream.ts index a7cbce3..0f46a37 100644 --- a/src/stream.ts +++ b/src/stream.ts @@ -11,7 +11,8 @@ export class Streamer { private readTimeoutCheckerId: any private connectionOpened = false private disconnectEventEmitted = false - private reconnectAttempts = 0 + private reconnectAttempts = 0 + constructor( private eventBus: Emitter, @@ -22,8 +23,10 @@ export class Streamer { private fallbackPoller: Poller, private logDebug: (...data: any[]) => void, private logError: (...data: any[]) => void, - private eventCallback: (e: StreamEvent) => void - ) {} + private eventCallback: (e: StreamEvent) => void, + private maxRetries: number + +) {} start() { const processData = (data: any): void => { diff --git a/src/types.ts b/src/types.ts index 6a95b7c..d54a15a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -144,6 +144,13 @@ export interface Options { * @default console */ logger?: Logger + + /** + * By default, the stream will attempt to reconnect indefinitely if it disconnects. Use this option to limit + * the number of attempts it will make. + */ + maxStreamingRetries?: number; // add this line + } export interface MetricsInfo { diff --git a/src/utils.ts b/src/utils.ts index aba4d9a..205fc24 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -10,7 +10,8 @@ export const defaultOptions: Options = { eventsSyncInterval: MIN_EVENTS_SYNC_INTERVAL, pollingInterval: MIN_POLLING_INTERVAL, streamEnabled: true, - cache: false + cache: false, + maxStreamingRetries: Infinity } export const getConfiguration = (options: Options): Options => { From 0e7a0c6c81f471b032cc5bd85cc538cb252a733c Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Mon, 29 Jul 2024 12:20:53 -0300 Subject: [PATCH 02/11] FFM-11788 Add max stream retry to stream.ts --- src/stream.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stream.ts b/src/stream.ts index 0f46a37..44ed9b2 100644 --- a/src/stream.ts +++ b/src/stream.ts @@ -13,7 +13,6 @@ export class Streamer { private disconnectEventEmitted = false private reconnectAttempts = 0 - constructor( private eventBus: Emitter, private configurations: Options, @@ -25,8 +24,7 @@ export class Streamer { private logError: (...data: any[]) => void, private eventCallback: (e: StreamEvent) => void, private maxRetries: number - -) {} + ) {} start() { const processData = (data: any): void => { @@ -63,7 +61,9 @@ export class Streamer { ) } - setTimeout(() => this.start(), reconnectDelayMs) + if (this.reconnectAttempts < this.maxRetries) { + setTimeout(() => this.start(), reconnectDelayMs) + } } const onFailed = (msg: string) => { From 5c89f2c6b7c718046218aadb089b5a199594fc13 Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Mon, 29 Jul 2024 12:46:15 -0300 Subject: [PATCH 03/11] FFM-11788 Log if we stay in polling mode --- src/stream.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/stream.ts b/src/stream.ts index 44ed9b2..69c9eb1 100644 --- a/src/stream.ts +++ b/src/stream.ts @@ -12,6 +12,7 @@ export class Streamer { private connectionOpened = false private disconnectEventEmitted = false private reconnectAttempts = 0 + private retriesExhausted: boolean = false constructor( private eventBus: Emitter, @@ -61,12 +62,24 @@ export class Streamer { ) } - if (this.reconnectAttempts < this.maxRetries) { - setTimeout(() => this.start(), reconnectDelayMs) + if (this.reconnectAttempts >= this.maxRetries) { + this.retriesExhausted = true + if (this.configurations.pollingEnabled) { + this.logErrorMessage('Max streaming retries reached. Staying in polling mode.') + } else { + this.logErrorMessage('Max streaming retries reached.') + } + return } + + setTimeout(() => this.start(), reconnectDelayMs) } const onFailed = (msg: string) => { + if (this.retriesExhausted) { + return + } + if (!!msg) { this.logDebugMessage('Stream has issue', msg) } From fc480d8310a36968785b9cc072024a3d34a9700f Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Mon, 29 Jul 2024 14:40:34 -0300 Subject: [PATCH 04/11] FFM-11788 Add tests for streaming class --- src/__tests__/stream.test.ts | 194 +++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 src/__tests__/stream.test.ts diff --git a/src/__tests__/stream.test.ts b/src/__tests__/stream.test.ts new file mode 100644 index 0000000..2f63a44 --- /dev/null +++ b/src/__tests__/stream.test.ts @@ -0,0 +1,194 @@ +import { Streamer } from '../stream' +import type { Options } from '../types' +import { Event } from '../types' +import { getRandom } from '../utils' +import type { Emitter } from 'mitt' +import type Poller from "../poller"; + +jest.useFakeTimers() + +jest.mock('../utils.ts', () => ({ + getRandom: jest.fn() +})) + +const mockEventBus: Emitter = { + emit: jest.fn(), + on: jest.fn(), + off: jest.fn(), + all: new Map() +} + +const mockXHR = { + open: jest.fn(), + setRequestHeader: jest.fn(), + send: jest.fn(), + abort: jest.fn(), + status: 0, + responseText: '', + onload: null, + onerror: null, + onprogress: null, + onabort: null, + ontimeout: null +} + +global.XMLHttpRequest = jest.fn(() => mockXHR) as unknown as jest.MockedClass + +const logError = jest.fn() +const logDebug = jest.fn() + +const getStreamer = (overrides: Partial = {}): Streamer => { + const options: Options = { + baseUrl: 'http://test', + eventUrl: 'http://event', + pollingInterval: 60000, + debug: true, + pollingEnabled: true, + streamEnabled: true, + ...overrides + } + + return new Streamer( + mockEventBus, + options, + `${options.baseUrl}/stream`, + 'test-api-key', + { 'Test-Header': 'value' }, + { start: jest.fn(), stop: jest.fn(), isPolling: jest.fn() } as unknown as Poller, + logDebug, + logError, + jest.fn(), + 3 + ) +} + +describe('Streamer', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + it('should connect and emit CONNECTED event', () => { + const streamer = getStreamer() + + streamer.start() + expect(mockXHR.open).toHaveBeenCalledWith('GET', 'http://test/stream') + expect(mockXHR.send).toHaveBeenCalled() + + mockXHR.onprogress({} as ProgressEvent) + expect(mockEventBus.emit).toHaveBeenCalledWith(Event.CONNECTED) + }) + + it('should retry connecting on error and eventually fallback to polling', () => { + const streamer = getStreamer() + + streamer.start() + expect(mockXHR.send).toHaveBeenCalled() + + for (let i = 0; i < 3; i++) { + mockXHR.onerror({} as ProgressEvent) + jest.advanceTimersByTime(getRandom(1000, 10000)) + } + + expect(mockEventBus.emit).toHaveBeenCalledWith(Event.DISCONNECTED) + expect(logError).toHaveBeenCalledWith('Streaming: Max streaming retries reached. Staying in polling mode.') + }) + + it('should not retry after max retries are exhausted', () => { + const streamer = getStreamer() + + streamer.start() + expect(mockXHR.send).toHaveBeenCalled() + + for (let i = 0; i < 3; i++) { + mockXHR.onerror({} as ProgressEvent) + jest.advanceTimersByTime(getRandom(1000, 10000)) + } + + mockXHR.onerror({} as ProgressEvent) + expect(logError).toHaveBeenCalledWith('Streaming: Max streaming retries reached. Staying in polling mode.') + expect(mockEventBus.emit).toHaveBeenCalledWith(Event.DISCONNECTED) + expect(mockXHR.send).toHaveBeenCalledTimes(3) // Should not send after max retries + }) + + it('should fallback to polling on stream failure', () => { + const poller = { start: jest.fn(), stop: jest.fn(), isPolling: jest.fn() } as unknown as Poller + const streamer = new Streamer( + mockEventBus, + { baseUrl: 'http://test', eventUrl: 'http://event', pollingEnabled: true, streamEnabled: true, debug: true }, + 'http://test/stream', + 'test-api-key', + { 'Test-Header': 'value' }, + poller, + logDebug, + logError, + jest.fn(), + 3 + ) + + streamer.start() + expect(mockXHR.send).toHaveBeenCalled() + + mockXHR.onerror({} as ProgressEvent) + jest.advanceTimersByTime(getRandom(1000, 10000)) + + expect(poller.start).toHaveBeenCalled() + expect(logDebug).toHaveBeenCalledWith('Streaming: Falling back to polling mode while stream recovers') + }) + + it('should stop polling when close is called if in fallback polling mode', () => { + const poller = { start: jest.fn(), stop: jest.fn(), isPolling: jest.fn().mockReturnValue(true) } as unknown as Poller + const streamer = new Streamer( + mockEventBus, + { baseUrl: 'http://test', eventUrl: 'http://event', pollingEnabled: true, streamEnabled: true, debug: true }, + 'http://test/stream', + 'test-api-key', + { 'Test-Header': 'value' }, + poller, + logDebug, + logError, + jest.fn(), + 3 + ) + + streamer.start() + expect(mockXHR.send).toHaveBeenCalled() + + mockXHR.onerror({} as ProgressEvent) + // Simulate stream failure and fallback to polling + mockXHR.onerror({} as ProgressEvent) + // jest.advanceTimersByTime(getRandom(1000, 10000)) + + // Ensure polling has started + expect(poller.start).toHaveBeenCalled() + + // Now close the streamer + streamer.close() + + expect(mockXHR.abort).toHaveBeenCalled() + expect(poller.stop).toHaveBeenCalled() + expect(mockEventBus.emit).toHaveBeenCalledWith(Event.STOPPED) + }) + + it('should stop streaming but not call poller.stop if not in fallback polling mode when close is called', () => { + const poller = { start: jest.fn(), stop: jest.fn(), isPolling: jest.fn().mockReturnValue(false) } as unknown as Poller + const streamer = new Streamer( + mockEventBus, + { baseUrl: 'http://test', eventUrl: 'http://event', pollingEnabled: true, streamEnabled: true, debug: true }, + 'http://test/stream', + 'test-api-key', + { 'Test-Header': 'value' }, + poller, + logDebug, + logError, + jest.fn(), + 3 + ) + + streamer.start() + streamer.close() + + expect(mockXHR.abort).toHaveBeenCalled() + expect(poller.stop).not.toHaveBeenCalled() + expect(mockEventBus.emit).toHaveBeenCalledWith(Event.STOPPED) + }) +}) From 2bea6aaf191e95c4119f46b345e74e111d581e0c Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Mon, 29 Jul 2024 14:55:51 -0300 Subject: [PATCH 05/11] FFM-11788 Add tests for streaming class --- src/__tests__/stream.test.ts | 56 +++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/src/__tests__/stream.test.ts b/src/__tests__/stream.test.ts index 2f63a44..30a7c17 100644 --- a/src/__tests__/stream.test.ts +++ b/src/__tests__/stream.test.ts @@ -1,7 +1,7 @@ import { Streamer } from '../stream' import type { Options } from '../types' import { Event } from '../types' -import { getRandom } from '../utils' +import {getRandom} from '../utils' import type { Emitter } from 'mitt' import type Poller from "../poller"; @@ -37,7 +37,7 @@ global.XMLHttpRequest = jest.fn(() => mockXHR) as unknown as jest.MockedClass = {}): Streamer => { +const getStreamer = (maxRetries: number, overrides: Partial = {}): Streamer => { const options: Options = { baseUrl: 'http://test', eventUrl: 'http://event', @@ -58,7 +58,7 @@ const getStreamer = (overrides: Partial = {}): Streamer => { logDebug, logError, jest.fn(), - 3 + maxRetries ) } @@ -68,7 +68,7 @@ describe('Streamer', () => { }) it('should connect and emit CONNECTED event', () => { - const streamer = getStreamer() + const streamer = getStreamer(3) streamer.start() expect(mockXHR.open).toHaveBeenCalledWith('GET', 'http://test/stream') @@ -79,7 +79,7 @@ describe('Streamer', () => { }) it('should retry connecting on error and eventually fallback to polling', () => { - const streamer = getStreamer() + const streamer = getStreamer(3) streamer.start() expect(mockXHR.send).toHaveBeenCalled() @@ -94,7 +94,7 @@ describe('Streamer', () => { }) it('should not retry after max retries are exhausted', () => { - const streamer = getStreamer() + const streamer = getStreamer(3) streamer.start() expect(mockXHR.send).toHaveBeenCalled() @@ -122,7 +122,7 @@ describe('Streamer', () => { logDebug, logError, jest.fn(), - 3 + Infinity, ) streamer.start() @@ -136,7 +136,11 @@ describe('Streamer', () => { }) it('should stop polling when close is called if in fallback polling mode', () => { - const poller = { start: jest.fn(), stop: jest.fn(), isPolling: jest.fn().mockReturnValue(true) } as unknown as Poller + const poller = { start: jest.fn(), stop: jest.fn(), isPolling: jest.fn() } as unknown as Poller + ;(poller.isPolling as jest.Mock) + .mockImplementationOnce(() => false) + .mockImplementationOnce(() => true) + const streamer = new Streamer( mockEventBus, { baseUrl: 'http://test', eventUrl: 'http://event', pollingEnabled: true, streamEnabled: true, debug: true }, @@ -153,10 +157,9 @@ describe('Streamer', () => { streamer.start() expect(mockXHR.send).toHaveBeenCalled() - mockXHR.onerror({} as ProgressEvent) // Simulate stream failure and fallback to polling mockXHR.onerror({} as ProgressEvent) - // jest.advanceTimersByTime(getRandom(1000, 10000)) + jest.advanceTimersByTime(getRandom(1000, 10000)) // Ensure polling has started expect(poller.start).toHaveBeenCalled() @@ -191,4 +194,37 @@ describe('Streamer', () => { expect(poller.stop).not.toHaveBeenCalled() expect(mockEventBus.emit).toHaveBeenCalledWith(Event.STOPPED) }) + + it('should retry indefinitely if maxRetries is set to Infinity', () => { + const streamer = getStreamer(Infinity) + + streamer.start() + expect(mockXHR.send).toHaveBeenCalled() + + for (let i = 0; i < 100; i++) { + mockXHR.onerror({} as ProgressEvent) + jest.advanceTimersByTime(getRandom(1000, 10000)) + } + + expect(logError).not.toHaveBeenCalledWith('Streaming: Max streaming retries reached. Staying in polling mode.') + expect(mockXHR.send).toHaveBeenCalledTimes(101) + }) + + it('should reconnect successfully after multiple failures', () => { + const streamer = getStreamer(5) + + streamer.start() + expect(mockXHR.send).toHaveBeenCalled() + + for (let i = 0; i < 3; i++) { + mockXHR.onerror({} as ProgressEvent) + jest.advanceTimersByTime(getRandom(1000, 10000)) + } + + // Simulate a successful connection on the next attempt + mockXHR.onprogress({} as ProgressEvent) + + expect(mockEventBus.emit).toHaveBeenCalledWith(Event.CONNECTED) + expect(mockXHR.send).toHaveBeenCalledTimes(4) // Should attempt to reconnect 3 times before succeeding + }) }) From 36346b8945d3a4e1b12aad91eda935cf29f68713 Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Mon, 29 Jul 2024 15:22:14 -0300 Subject: [PATCH 06/11] FFM-11788 Default tests to infinite retries --- src/__tests__/stream.test.ts | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/__tests__/stream.test.ts b/src/__tests__/stream.test.ts index 30a7c17..c3bca50 100644 --- a/src/__tests__/stream.test.ts +++ b/src/__tests__/stream.test.ts @@ -1,7 +1,7 @@ import { Streamer } from '../stream' import type { Options } from '../types' import { Event } from '../types' -import {getRandom} from '../utils' +import { getRandom } from '../utils' import type { Emitter } from 'mitt' import type Poller from "../poller"; @@ -37,7 +37,7 @@ global.XMLHttpRequest = jest.fn(() => mockXHR) as unknown as jest.MockedClass = {}): Streamer => { +const getStreamer = (overrides: Partial = {}, maxRetries: number = Infinity): Streamer => { const options: Options = { baseUrl: 'http://test', eventUrl: 'http://event', @@ -68,7 +68,7 @@ describe('Streamer', () => { }) it('should connect and emit CONNECTED event', () => { - const streamer = getStreamer(3) + const streamer = getStreamer({}, 3) streamer.start() expect(mockXHR.open).toHaveBeenCalledWith('GET', 'http://test/stream') @@ -78,8 +78,26 @@ describe('Streamer', () => { expect(mockEventBus.emit).toHaveBeenCalledWith(Event.CONNECTED) }) + it('should reconnect successfully after multiple failures', () => { + const streamer = getStreamer({}, 5) + + streamer.start() + expect(mockXHR.send).toHaveBeenCalled() + + for (let i = 0; i < 3; i++) { + mockXHR.onerror({} as ProgressEvent) + jest.advanceTimersByTime(getRandom(1000, 10000)) + } + + // Simulate a successful connection on the next attempt + mockXHR.onprogress({} as ProgressEvent) + + expect(mockEventBus.emit).toHaveBeenCalledWith(Event.CONNECTED) + expect(mockXHR.send).toHaveBeenCalledTimes(4) // Should attempt to reconnect 3 times before succeeding + }) + it('should retry connecting on error and eventually fallback to polling', () => { - const streamer = getStreamer(3) + const streamer = getStreamer() streamer.start() expect(mockXHR.send).toHaveBeenCalled() @@ -90,11 +108,10 @@ describe('Streamer', () => { } expect(mockEventBus.emit).toHaveBeenCalledWith(Event.DISCONNECTED) - expect(logError).toHaveBeenCalledWith('Streaming: Max streaming retries reached. Staying in polling mode.') }) it('should not retry after max retries are exhausted', () => { - const streamer = getStreamer(3) + const streamer = getStreamer({}, 3) streamer.start() expect(mockXHR.send).toHaveBeenCalled() @@ -122,7 +139,7 @@ describe('Streamer', () => { logDebug, logError, jest.fn(), - Infinity, + Infinity ) streamer.start() @@ -196,7 +213,7 @@ describe('Streamer', () => { }) it('should retry indefinitely if maxRetries is set to Infinity', () => { - const streamer = getStreamer(Infinity) + const streamer = getStreamer() streamer.start() expect(mockXHR.send).toHaveBeenCalled() @@ -211,7 +228,7 @@ describe('Streamer', () => { }) it('should reconnect successfully after multiple failures', () => { - const streamer = getStreamer(5) + const streamer = getStreamer({}, 5) streamer.start() expect(mockXHR.send).toHaveBeenCalled() From 1e1625999d4b46369b5da1329576e019d6af5ee1 Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Mon, 29 Jul 2024 15:28:57 -0300 Subject: [PATCH 07/11] FFM-11788 Update readme --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 8e1c807..52bb912 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,32 @@ const client = initialize( ) ``` +Max Stream Retries +You can configure the maximum number of streaming retries before the SDK stops attempting to reconnect or falls back to polling (if enabled). The maxRetries option can be set to any positive number or Infinity for unlimited retries (which is the default). + +```typescript +const options = { + maxRetries: 5, // Set the maximum number of retries for streaming. Default is Infinity. + streamEnabled: true, + pollingEnabled: true, + pollingInterval: 60000, +} + +const client = initialize( + 'YOUR_SDK_KEY', + { + identifier: 'Harness1', + attributes: { + lastUpdated: Date(), + host: location.href + } + }, + options +) + +``` +If maxRetries is reached and pollingEnabled is true, the SDK will stay in polling mode. If pollingEnabled is false, the SDK will not poll, and evaluations will not be updated until the SDK Client is initialized again, for example if the app or page is restarted. + ## Listening to events from the `client` instance. ```typescript From d99382240d037eff04d00e84aa5c965f3e7ade2e Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Mon, 29 Jul 2024 15:32:14 -0300 Subject: [PATCH 08/11] FFM-11788 Change config name --- src/index.ts | 2 +- src/types.ts | 2 +- src/utils.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index dcd2705..2a3b038 100644 --- a/src/index.ts +++ b/src/index.ts @@ -544,7 +544,7 @@ const initialize = (apiKey: string, target: Target, options?: Options): Result = handleSegmentEvent(event) } }, - configurations.maxStreamingRetries + configurations.maxStreamRetries ) eventSource.start() } diff --git a/src/types.ts b/src/types.ts index d54a15a..b1582ff 100644 --- a/src/types.ts +++ b/src/types.ts @@ -149,7 +149,7 @@ export interface Options { * By default, the stream will attempt to reconnect indefinitely if it disconnects. Use this option to limit * the number of attempts it will make. */ - maxStreamingRetries?: number; // add this line + maxStreamRetries?: number; // add this line } diff --git a/src/utils.ts b/src/utils.ts index 205fc24..f543727 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -11,7 +11,7 @@ export const defaultOptions: Options = { pollingInterval: MIN_POLLING_INTERVAL, streamEnabled: true, cache: false, - maxStreamingRetries: Infinity + maxStreamRetries: Infinity } export const getConfiguration = (options: Options): Options => { From 1ebf405a4762c191fa901c51f00de989f4c9bff8 Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Wed, 31 Jul 2024 11:26:45 -0300 Subject: [PATCH 09/11] FFM-11788 Remove typo --- src/types.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/types.ts b/src/types.ts index b1582ff..127e7d7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -149,8 +149,7 @@ export interface Options { * By default, the stream will attempt to reconnect indefinitely if it disconnects. Use this option to limit * the number of attempts it will make. */ - maxStreamRetries?: number; // add this line - + maxStreamRetries?: number } export interface MetricsInfo { From 11080b912c4fb166b6ca3559cda4444cc32f3388 Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Wed, 31 Jul 2024 11:59:50 -0300 Subject: [PATCH 10/11] FFM-11788 Update error log --- src/stream.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/stream.ts b/src/stream.ts index 69c9eb1..49a169f 100644 --- a/src/stream.ts +++ b/src/stream.ts @@ -67,7 +67,9 @@ export class Streamer { if (this.configurations.pollingEnabled) { this.logErrorMessage('Max streaming retries reached. Staying in polling mode.') } else { - this.logErrorMessage('Max streaming retries reached.') + this.logErrorMessage( + 'Max streaming retries reached. Polling mode is disabled and will receive no further flag updates until SDK client is restarted.' + ) } return } From 841b4af371e45360769150f57f63dc6925d08bb4 Mon Sep 17 00:00:00 2001 From: Erdi Rowlands Date: Wed, 31 Jul 2024 12:27:12 -0300 Subject: [PATCH 11/11] FFM-11788 RC prep --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 78168e2..5407278 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@harnessio/ff-javascript-client-sdk", - "version": "1.26.3", + "version": "1.27.0-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@harnessio/ff-javascript-client-sdk", - "version": "1.26.3", + "version": "1.27.0-rc.0", "license": "Apache-2.0", "dependencies": { "jwt-decode": "^3.1.2", diff --git a/package.json b/package.json index 2a2f1b0..dbcc5c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@harnessio/ff-javascript-client-sdk", - "version": "1.26.3", + "version": "1.27.0-rc.0", "author": "Harness", "license": "Apache-2.0", "main": "dist/sdk.cjs.js",