UNPKG

@splitsoftware/splitio-commons

Version:
97 lines (96 loc) 6.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.segmentChangesUpdaterFactory = void 0; var constants_1 = require("../../../readiness/constants"); var constants_2 = require("../../../logger/constants"); var timeout_1 = require("../../../utils/promise/timeout"); /** * Factory of SegmentChanges updater, a task that: * - fetches segment changes using `segmentChangesFetcher` * - updates `segmentsCache` * - uses `segmentsEventEmitter` to emit events related to segments data updates * * @param log - logger instance * @param segmentChangesFetcher - fetcher of `/segmentChanges` * @param segments - segments storage, with sync or async methods * @param readiness - optional readiness manager. Not required for synchronizer or producer mode. */ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness, requestTimeoutBeforeReady, retriesOnFailureBeforeReady) { var readyOnAlreadyExistentState = true; function _promiseDecorator(promise) { if (readyOnAlreadyExistentState && requestTimeoutBeforeReady) promise = (0, timeout_1.timeout)(requestTimeoutBeforeReady, promise); return promise; } function updateSegment(segmentName, noCache, till, fetchOnlyNew, retries) { log.debug("".concat(constants_2.LOG_PREFIX_SYNC, "Processing segment ").concat(segmentName)); var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName)); return sincePromise.then(function (since) { // if fetchOnlyNew flag, avoid processing already fetched segments return fetchOnlyNew && since !== undefined ? false : segmentChangesFetcher(since || -1, segmentName, noCache, till, _promiseDecorator).then(function (changes) { return Promise.all(changes.map(function (x) { log.debug("".concat(constants_2.LOG_PREFIX_SYNC, "Processing ").concat(segmentName, " with till = ").concat(x.till, ". Added: ").concat(x.added.length, ". Removed: ").concat(x.removed.length)); return segments.update(segmentName, x.added, x.removed, x.till); })).then(function (updates) { return updates.some(function (update) { return update; }); }); }).catch(function (error) { if (retries) { log.warn("".concat(constants_2.LOG_PREFIX_SYNC, "Retrying fetch of segment ").concat(segmentName, " (attempt #").concat(retries, "). Reason: ").concat(error)); return updateSegment(segmentName, noCache, till, fetchOnlyNew, retries - 1); } throw error; }); }); } /** * Segments updater returns a promise that resolves with a `false` boolean value if it fails at least to fetch a segment or synchronize it with the storage. * Thus, a false result doesn't imply that SDK_SEGMENTS_ARRIVED was not emitted. * Returned promise will not be rejected. * * @param fetchOnlyNew - if true, only fetch the segments that not exists, i.e., which `changeNumber` is equal to -1. * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE or RB_SEGMENT_UPDATE notifications. * @param segmentName - segment name to fetch. By passing `undefined` it fetches the list of segments registered at the storage * @param noCache - true to revalidate data to fetch on a SEGMENT_UPDATE notifications. * @param till - till target for the provided segmentName, for CDN bypass. */ return function segmentChangesUpdater(fetchOnlyNew, segmentName, noCache, till) { log.debug("".concat(constants_2.LOG_PREFIX_SYNC, "Started segments update")); // If not a segment name provided, read list of available segments names to be updated. var segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments()); return segmentsPromise.then(function (segmentNames) { var updaters = segmentNames.map(function (segmentName) { return updateSegment(segmentName, noCache, till, fetchOnlyNew, readyOnAlreadyExistentState ? retriesOnFailureBeforeReady : 0); }); return Promise.all(updaters).then(function (shouldUpdateFlags) { // if at least one segment fetch succeeded, mark segments ready if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) { readyOnAlreadyExistentState = false; if (readiness && !fetchOnlyNew) { var metadata = { type: constants_1.SEGMENTS_UPDATE, names: [] }; readiness.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED, metadata); } } return true; }); }) // Handles rejected promises at `segmentChangesFetcher`, `segments.getRegisteredSegments` and other segment storage operations. .catch(function (error) { if (error && error.statusCode === 403) { // If the operation is forbidden, it may be due to permissions. Destroy the SDK instance. // @TODO although factory status is destroyed, synchronization is not stopped if (readiness) readiness.setDestroyed(); log.error("".concat(constants_2.LOG_PREFIX_INSTANTIATION, ": you passed a client-side type authorizationKey, please grab an SDK Key from Harness FME UI that is of type server-side.")); } else { log.warn("".concat(constants_2.LOG_PREFIX_SYNC, "Error while doing fetch of segments. ").concat(error)); } return false; }); }; } exports.segmentChangesUpdaterFactory = segmentChangesUpdaterFactory;