UNPKG

@splitsoftware/splitio-commons

Version:
130 lines (129 loc) 5.8 kB
import { STREAMING_PARSING_SPLIT_UPDATE } from '../../../logger/constants'; import { SDK_DEFINITIONS_ARRIVED } from '../../../readiness/constants'; import { Backoff } from '../../../utils/Backoff'; import { SPLITS } from '../../../utils/constants'; import { RB_SEGMENT_UPDATE } from '../constants'; import { parseFFUpdatePayload } from '../parseUtils'; import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT, FETCH_BACKOFF_MAX_RETRIES } from './constants'; /** * DefinitionsUpdateWorker factory */ export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker) { var ff = DefinitionsUpdateWorker(storage.definitions); var rbs = DefinitionsUpdateWorker(storage.rbSegments); function DefinitionsUpdateWorker(cache) { var maxChangeNumber = -1; var handleNewEvent = false; var isHandlingEvent; var cdnBypass; var instantUpdate; var backoff = new Backoff(__handleDefinitionUpdateCall, FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT); function __handleDefinitionUpdateCall() { isHandlingEvent = true; if (maxChangeNumber > cache.getChangeNumber()) { handleNewEvent = false; // fetch splits revalidating data if cached definitionsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined, instantUpdate).then(function () { if (!isHandlingEvent) return; // halt if `stop` has been called if (handleNewEvent) { __handleDefinitionUpdateCall(); } else { if (instantUpdate) telemetryTracker.trackUpdatesFromSSE(SPLITS); var attempts = backoff.attempts + 1; if (ff.isSync() && rbs.isSync()) { log.debug("Refresh completed".concat(cdnBypass ? ' bypassing the CDN' : '', " in ").concat(attempts, " attempts.")); isHandlingEvent = false; return; } if (attempts < FETCH_BACKOFF_MAX_RETRIES) { backoff.scheduleCall(); return; } if (cdnBypass) { log.debug("No changes fetched after ".concat(attempts, " attempts with CDN bypassed.")); isHandlingEvent = false; } else { backoff.reset(); cdnBypass = true; __handleDefinitionUpdateCall(); } } }); } else { isHandlingEvent = false; } } return { /** * Invoked by NotificationProcessor on SPLIT_UPDATE or RB_SEGMENT_UPDATE event * * @param changeNumber - change number of the notification */ put: function (_a, payload) { var changeNumber = _a.changeNumber, pcn = _a.pcn, type = _a.type; var currentChangeNumber = cache.getChangeNumber(); if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return; maxChangeNumber = changeNumber; handleNewEvent = true; cdnBypass = false; instantUpdate = undefined; if (payload && currentChangeNumber === pcn) { instantUpdate = { payload: payload, changeNumber: changeNumber, type: type }; } if (backoff.timeoutID || !isHandlingEvent) __handleDefinitionUpdateCall(); backoff.reset(); }, stop: function () { isHandlingEvent = false; backoff.reset(); }, isSync: function () { return maxChangeNumber <= cache.getChangeNumber(); } }; } return { put: function (parsedData) { if (parsedData.d && parsedData.c !== undefined) { try { var payload = parseFFUpdatePayload(parsedData.c, parsedData.d); if (payload) { (parsedData.type === RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload); return; } } catch (e) { log.warn(STREAMING_PARSING_SPLIT_UPDATE, [parsedData.type, e]); } } (parsedData.type === RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData); }, /** * Invoked by NotificationProcessor on SPLIT_KILL event * * @param changeNumber - change number of the notification * @param splitName - name of split to kill * @param defaultTreatment - default treatment value */ killDefinition: function (_a) { var changeNumber = _a.changeNumber, splitName = _a.splitName, defaultTreatment = _a.defaultTreatment; if (storage.definitions.killLocally(splitName, defaultTreatment, changeNumber)) { // trigger an SDK_UPDATE if Split was killed locally definitionsEventEmitter.emit(SDK_DEFINITIONS_ARRIVED, true); } // queues the SplitChanges fetch (only if changeNumber is newer) ff.put({ changeNumber: changeNumber }); }, stop: function () { ff.stop(); rbs.stop(); } }; }