Skip to content

Commit d51e8f1

Browse files
Update segmentChangesUpdater to timeout and retry on startup
1 parent 3b99e8a commit d51e8f1

File tree

8 files changed

+31
-14
lines changed

8 files changed

+31
-14
lines changed

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2.8.0 (October XX, 2025)
2+
- Updated the SDK’s initial synchronization in Node.js (server-side) to use `startup.requestTimeoutBeforeReady` and `startup.retriesOnFailureBeforeReady` to control the timeout and retry behavior of segment requests.
3+
14
2.7.1 (October 8, 2025)
25
- Bugfix - Update `debug` option to support log levels when `logger` option is used.
36

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@splitsoftware/splitio-commons",
3-
"version": "2.7.1",
3+
"version": "2.7.2-rc.0",
44
"description": "Split JavaScript SDK common components",
55
"main": "cjs/index.js",
66
"module": "esm/index.js",

src/logger/messages/info.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const codesInfo: [number, string][] = codesWarn.concat([
2222
[c.POLLING_SMART_PAUSING, c.LOG_PREFIX_SYNC_POLLING + 'Turning segments data polling %s.'],
2323
[c.POLLING_START, c.LOG_PREFIX_SYNC_POLLING + 'Starting polling'],
2424
[c.POLLING_STOP, c.LOG_PREFIX_SYNC_POLLING + 'Stopping polling'],
25-
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying download of feature flags #%s. Reason: %s'],
25+
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying fetch of feature flags (attempt #%s). Reason: %s'],
2626
[c.SUBMITTERS_PUSH_FULL_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full %s queue and resetting timer.'],
2727
[c.SUBMITTERS_PUSH, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Pushing %s.'],
2828
[c.SUBMITTERS_PUSH_PAGE_HIDDEN, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing %s because page became hidden.'],

src/logger/messages/warn.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const codesWarn: [number, string][] = codesError.concat([
66
[c.ENGINE_VALUE_INVALID, c.LOG_PREFIX_ENGINE_VALUE + 'Value %s doesn\'t match with expected type.'],
77
[c.ENGINE_VALUE_NO_ATTRIBUTES, c.LOG_PREFIX_ENGINE_VALUE + 'Defined attribute `%s`. No attributes received.'],
88
// synchronizer
9-
[c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying download of segments #%s. Reason: %s'],
9+
[c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying fetch of memberships (attempt #%s). Reason: %s'],
1010
[c.SYNC_SPLITS_FETCH_FAILS, c.LOG_PREFIX_SYNC_SPLITS + 'Error while doing fetch of feature flags. %s'],
1111
[c.STREAMING_PARSING_ERROR_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE error notification: %s'],
1212
[c.STREAMING_PARSING_MESSAGE_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE message notification: %s'],

src/sync/polling/syncTasks/segmentsSyncTask.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export function segmentsSyncTaskFactory(
2323
segmentChangesFetcherFactory(fetchSegmentChanges),
2424
storage.segments,
2525
readiness,
26+
settings.startup.requestTimeoutBeforeReady,
27+
settings.startup.retriesOnFailureBeforeReady,
2628
),
2729
settings.scheduler.segmentsRefreshRate,
2830
'segmentChangesUpdater'

src/sync/polling/updaters/segmentChangesUpdater.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { IReadinessManager } from '../../../readiness/types';
44
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
55
import { ILogger } from '../../../logger/types';
66
import { LOG_PREFIX_INSTANTIATION, LOG_PREFIX_SYNC_SEGMENTS } from '../../../logger/constants';
7+
import { timeout } from '../../../utils/promise/timeout';
78

89
type ISegmentChangesUpdater = (fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number) => Promise<boolean>
910

@@ -23,25 +24,38 @@ export function segmentChangesUpdaterFactory(
2324
segmentChangesFetcher: ISegmentChangesFetcher,
2425
segments: ISegmentsCacheBase,
2526
readiness?: IReadinessManager,
27+
requestTimeoutBeforeReady?: number,
28+
retriesOnFailureBeforeReady?: number,
2629
): ISegmentChangesUpdater {
2730

2831
let readyOnAlreadyExistentState = true;
2932

30-
function updateSegment(segmentName: string, noCache?: boolean, till?: number, fetchOnlyNew?: boolean): Promise<boolean> {
33+
function _promiseDecorator<T>(promise: Promise<T>) {
34+
if (readyOnAlreadyExistentState && requestTimeoutBeforeReady) promise = timeout(requestTimeoutBeforeReady, promise);
35+
return promise;
36+
}
37+
38+
function updateSegment(segmentName: string, noCache?: boolean, till?: number, fetchOnlyNew?: boolean, retries?: number): Promise<boolean> {
3139
log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processing segment ${segmentName}`);
3240
let sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
3341

3442
return sincePromise.then(since => {
3543
// if fetchOnlyNew flag, avoid processing already fetched segments
3644
return fetchOnlyNew && since !== undefined ?
3745
false :
38-
segmentChangesFetcher(since || -1, segmentName, noCache, till).then((changes) => {
46+
segmentChangesFetcher(since || -1, segmentName, noCache, till, _promiseDecorator).then((changes) => {
3947
return Promise.all(changes.map(x => {
4048
log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processing ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`);
4149
return segments.update(segmentName, x.added, x.removed, x.till);
4250
})).then((updates) => {
4351
return updates.some(update => update);
4452
});
53+
}).catch(error => {
54+
if (retries) {
55+
log.warn(`${LOG_PREFIX_SYNC_SEGMENTS}Retrying fetch of segment ${segmentName} (attempt #${retries}). Reason: ${error}`);
56+
return updateSegment(segmentName, noCache, till, fetchOnlyNew, retries - 1);
57+
}
58+
throw error;
4559
});
4660
});
4761
}
@@ -63,8 +77,7 @@ export function segmentChangesUpdaterFactory(
6377
let segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
6478

6579
return segmentsPromise.then(segmentNames => {
66-
// Async fetchers
67-
const updaters = segmentNames.map(segmentName => updateSegment(segmentName, noCache, till, fetchOnlyNew));
80+
const updaters = segmentNames.map(segmentName => updateSegment(segmentName, noCache, till, fetchOnlyNew, readyOnAlreadyExistentState ? retriesOnFailureBeforeReady : 0));
6881

6982
return Promise.all(updaters).then(shouldUpdateFlags => {
7083
// if at least one segment fetch succeeded, mark segments ready

src/sync/polling/updaters/splitChangesUpdater.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ export function splitChangesUpdaterFactory(
120120
storage: Pick<IStorageBase, 'splits' | 'rbSegments' | 'segments' | 'save'>,
121121
splitFiltersValidation: ISplitFiltersValidation,
122122
splitsEventEmitter?: ISplitsEventEmitter,
123-
requestTimeoutBeforeReady: number = 0,
124-
retriesOnFailureBeforeReady: number = 0,
123+
requestTimeoutBeforeReady = 0,
124+
retriesOnFailureBeforeReady = 0,
125125
isClientSide?: boolean
126126
): SplitChangesUpdater {
127127
const { splits, rbSegments, segments } = storage;
@@ -201,14 +201,13 @@ export function splitChangesUpdaterFactory(
201201
});
202202
})
203203
.catch(error => {
204-
log.warn(SYNC_SPLITS_FETCH_FAILS, [error]);
205-
206204
if (startingUp && retriesOnFailureBeforeReady > retry) {
207205
retry += 1;
208-
log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
206+
log.warn(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
209207
return _splitChangesUpdater(sinces, retry);
210208
} else {
211209
startingUp = false;
210+
log.warn(SYNC_SPLITS_FETCH_FAILS, [error]);
212211
}
213212
return false;
214213
});

0 commit comments

Comments
 (0)