Skip to content

Commit 13f2dcf

Browse files
Merge pull request #409 from splitio/rb_segments_fixes
[Rule-based segments] Fixes and polishing
2 parents bfcd0c4 + b8bb5df commit 13f2dcf

File tree

6 files changed

+28
-9
lines changed

6 files changed

+28
-9
lines changed

CHANGES.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
2.3.0 (May XXX, 2025)
1+
2.3.0 (May 12, 2025)
22
- Added support for targeting rules based on rule-based segments.
33
- Updated the Redis storage to:
44
- Avoid lazy require of the `ioredis` dependency when the SDK is initialized, and

src/dtos/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ export interface IRBSegment {
210210
status: 'ACTIVE' | 'ARCHIVED',
211211
conditions?: ISplitCondition[],
212212
excluded?: {
213-
keys?: string[],
214-
segments?: IExcludedSegment[]
213+
keys?: string[] | null,
214+
segments?: IExcludedSegment[] | null
215215
}
216216
}
217217

src/evaluator/matchers/__tests__/rbsegment.spec.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ const STORED_RBSEGMENTS: Record<string, IRBSegment> = {
9595
changeNumber: 123,
9696
status: 'ACTIVE',
9797
excluded: {
98-
keys: [],
99-
segments: []
98+
keys: null,
99+
segments: null,
100100
},
101101
conditions: [{
102102
matcherGroup: {
@@ -167,6 +167,12 @@ const STORED_RBSEGMENTS: Record<string, IRBSegment> = {
167167
}
168168
}
169169
],
170+
},
171+
'rule_based_segment_without_conditions': {
172+
name: 'rule_based_segment_without_conditions',
173+
changeNumber: 123,
174+
status: 'ACTIVE',
175+
conditions: []
170176
}
171177
};
172178

@@ -291,6 +297,14 @@ describe.each([
291297

292298
// should support feature flag dependency matcher
293299
expect(await matcherTrueAlwaysOn({ key: 'a-key' }, evaluateFeature)).toBe(true); // Parent split returns one of the expected treatments, so the matcher returns true
300+
301+
const matcherTrueRuleBasedSegmentWithoutConditions = matcherFactory(loggerMock, {
302+
type: matcherTypes.IN_RULE_BASED_SEGMENT,
303+
value: 'rule_based_segment_without_conditions'
304+
} as IMatcherDto, mockStorageSync)!;
305+
306+
// should support rule-based segment without conditions
307+
expect(await matcherTrueRuleBasedSegmentWithoutConditions({ key: 'a-key' }, evaluateFeature)).toBe(false);
294308
});
295309

296310
});

src/evaluator/matchers/rbsegment.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export function ruleBasedSegmentMatcherContext(segmentName: string, storage: ISt
1515

1616
function matchConditions(rbsegment: IRBSegment) {
1717
const conditions = rbsegment.conditions || [];
18+
19+
if (!conditions.length) return false;
20+
1821
const evaluator = parser(log, conditions, storage);
1922

2023
const evaluation = evaluator(

src/services/splitHttpClient.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ERROR_HTTP, ERROR_CLIENT_CANNOT_GET_READY } from '../logger/constants';
44
import { ISettings } from '../types';
55
import { IPlatform } from '../sdkFactory/types';
66
import { decorateHeaders, removeNonISO88591 } from './decorateHeaders';
7+
import { timeout } from '../utils/promise/timeout';
78

89
const messageNoFetch = 'Global fetch API is not available.';
910

@@ -45,7 +46,8 @@ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFet
4546
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
4647
.then(response => {
4748
if (!response.ok) {
48-
return response.text().then(message => Promise.reject({ response, message }));
49+
// timeout after 100ms because `text()` promise doesn't settle in some implementations and cases (e.g. no content)
50+
return timeout(100, response.text()).then(message => Promise.reject({ response, message }), () => Promise.reject({ response }));
4951
}
5052
latencyTracker();
5153
return response;

src/sync/polling/fetchers/splitChangesFetcher.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { LOG_PREFIX_SYNC_SPLITS } from '../../../logger/constants';
1010
const PROXY_CHECK_INTERVAL_MILLIS_CS = 60 * 60 * 1000; // 1 hour in Client Side
1111
const PROXY_CHECK_INTERVAL_MILLIS_SS = 24 * PROXY_CHECK_INTERVAL_MILLIS_CS; // 24 hours in Server Side
1212

13-
function sdkEndpointOverriden(settings: ISettings) {
13+
function sdkEndpointOverridden(settings: ISettings) {
1414
return settings.urls.sdk !== base.urls.sdk;
1515
}
1616

@@ -42,8 +42,8 @@ export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges
4242
let splitsPromise = fetchSplitChanges(since, noCache, till, settings.sync.flagSpecVersion === FLAG_SPEC_VERSION ? rbSince : undefined)
4343
// Handle proxy error with spec 1.3
4444
.catch((err) => {
45-
if (err.statusCode === 400 && sdkEndpointOverriden(settings) && settings.sync.flagSpecVersion === FLAG_SPEC_VERSION) {
46-
log.error(LOG_PREFIX_SYNC_SPLITS + 'Proxy error detected. If you are using Split Proxy, please upgrade to latest version');
45+
if (err.statusCode === 400 && sdkEndpointOverridden(settings) && settings.sync.flagSpecVersion === FLAG_SPEC_VERSION) {
46+
log.error(LOG_PREFIX_SYNC_SPLITS + 'Proxy error detected. Retrying with spec 1.2. If you are using Split Proxy, please upgrade to latest version');
4747
lastProxyCheckTimestamp = Date.now();
4848
settings.sync.flagSpecVersion = '1.2'; // fallback to 1.2 spec
4949
return fetchSplitChanges(since, noCache, till); // retry request without rbSince

0 commit comments

Comments
 (0)