@splitsoftware/splitio-commons
Version:
Split JavaScript SDK common components
77 lines (76 loc) • 3.91 kB
JavaScript
import { timeout } from '../../../utils/promise/timeout';
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
import { MEMBERSHIPS_LS_UPDATE } from '../../streaming/constants';
/**
* factory of MySegments updater, a task that:
* - fetches mySegments using `mySegmentsFetcher`
* - updates `mySegmentsCache`
* - uses `segmentsEventEmitter` to emit events related to segments data updates
*/
export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, matchingKey) {
var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments, largeSegments = storage.largeSegments;
var readyOnAlreadyExistentState = true;
var startingUp = true;
/** timeout and telemetry decorator for `splitChangesFetcher` promise */
function _promiseDecorator(promise) {
if (startingUp)
promise = timeout(requestTimeoutBeforeReady, promise);
return promise;
}
// @TODO if allowing pluggable storages, handle async execution
function updateSegments(segmentsData) {
var shouldNotifyUpdate;
if (segmentsData.type !== undefined) {
shouldNotifyUpdate = segmentsData.type === MEMBERSHIPS_LS_UPDATE ?
largeSegments.resetSegments(segmentsData) :
segments.resetSegments(segmentsData);
}
else {
shouldNotifyUpdate = segments.resetSegments(segmentsData.ms || {});
shouldNotifyUpdate = largeSegments.resetSegments(segmentsData.ls || {}) || shouldNotifyUpdate;
}
// Notify update if required
if ((splits.usesSegments() || rbSegments.usesSegments()) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
readyOnAlreadyExistentState = false;
segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
}
}
function _mySegmentsUpdater(retry, segmentsData, noCache, till) {
var updaterPromise = segmentsData ?
// If segmentsData is provided, there is no need to fetch mySegments
new Promise(function (res) { updateSegments(segmentsData); res(true); }) :
// If not provided, fetch mySegments
mySegmentsFetcher(matchingKey, noCache, till, _promiseDecorator).then(function (segments) {
// Only when we have downloaded segments completely, we should not keep retrying anymore
startingUp = false;
updateSegments(segments);
return true;
});
return updaterPromise.catch(function (error) {
if (startingUp && retriesOnFailureBeforeReady > retry) {
retry += 1;
log.warn(SYNC_MYSEGMENTS_FETCH_RETRY, [retry, error]);
return _mySegmentsUpdater(retry); // no need to forward `segmentList` and `noCache` params
}
else {
startingUp = false;
}
return false;
});
}
/**
* MySegments updater returns a promise that resolves with a `false` boolean value if it fails to fetch mySegments or synchronize them with the storage.
* Returned promise will not be rejected.
*
* @param segmentsData - it can be:
* (1) the list of mySegments names to sync in the storage,
* (2) an object with a segment name and action (true: add, or false: delete) to update the storage,
* (3) or `undefined`, for which the updater will fetch mySegments in order to sync the storage.
* @param noCache - true to revalidate data to fetch
* @param till - query param to bypass CDN requests
*/
return function mySegmentsUpdater(segmentsData, noCache, till) {
return _mySegmentsUpdater(0, segmentsData, noCache, till);
};
}