UNPKG

@launchdarkly/js-server-sdk-common

Version:
118 lines 5.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const js_sdk_common_1 = require("@launchdarkly/js-sdk-common"); const BigSegmentStatusProviderImpl_1 = require("./BigSegmentStatusProviderImpl"); const LruCache_1 = require("./cache/LruCache"); const DEFAULT_STALE_AFTER_SECONDS = 120; const DEFAULT_STATUS_POLL_INTERVAL_SECONDS = 5; const DEFAULT_USER_CACHE_SIZE = 1000; const DEFAULT_USER_CACHE_TIME_SECONDS = 5; class BigSegmentsManager { constructor(_store, // The store will have been created before the manager is instantiated, so we do not need // it in the options at this stage. config, _logger, _crypto) { this._store = _store; this._logger = _logger; this._crypto = _crypto; this.statusProvider = new BigSegmentStatusProviderImpl_1.default(async () => this._pollStoreAndUpdateStatus()); this._staleTimeMs = (js_sdk_common_1.TypeValidators.Number.is(config.staleAfter) && config.staleAfter > 0 ? config.staleAfter : DEFAULT_STALE_AFTER_SECONDS) * 1000; const pollIntervalMs = (js_sdk_common_1.TypeValidators.Number.is(config.statusPollInterval) && config.statusPollInterval > 0 ? config.statusPollInterval : DEFAULT_STATUS_POLL_INTERVAL_SECONDS) * 1000; this._pollHandle = _store ? setInterval(() => this._pollStoreAndUpdateStatus(), pollIntervalMs) : null; if (_store) { this._cache = new LruCache_1.default({ max: config.userCacheSize || DEFAULT_USER_CACHE_SIZE, maxAge: (config.userCacheTime || DEFAULT_USER_CACHE_TIME_SECONDS) * 1000, }); } } close() { if (this._pollHandle) { clearInterval(this._pollHandle); this._pollHandle = undefined; } if (this._store) { this._store.close(); } } async getUserMembership(userKey) { var _a, _b, _c; if (!this._store) { return undefined; } const memberCache = (_a = this._cache) === null || _a === void 0 ? void 0 : _a.get(userKey); let membership; if (!memberCache) { try { membership = await this._store.getUserMembership(this._hashForUserKey(userKey)); const cacheItem = { membership }; (_b = this._cache) === null || _b === void 0 ? void 0 : _b.set(userKey, cacheItem); } catch (err) { (_c = this._logger) === null || _c === void 0 ? void 0 : _c.error(`Big Segment store membership query returned error: ${err}`); return [null, 'STORE_ERROR']; } } else { membership = memberCache.membership; } if (!this.statusProvider.getStatus()) { await this._pollStoreAndUpdateStatus(); } // Status will be present, because polling is done earlier in this method if it is not. const lastStatus = this.statusProvider.getStatus(); if (!lastStatus.available) { return [membership || null, 'STORE_ERROR']; } return [membership || null, lastStatus.stale ? 'STALE' : 'HEALTHY']; } async _pollStoreAndUpdateStatus() { var _a, _b, _c; if (!this._store) { this.statusProvider.setStatus({ available: false, stale: false }); return; } (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug('Querying Big Segment store status'); let newStatus; try { const metadata = await this._store.getMetadata(); newStatus = { available: true, stale: !metadata || !metadata.lastUpToDate || this._isStale(metadata.lastUpToDate), }; } catch (err) { (_b = this._logger) === null || _b === void 0 ? void 0 : _b.error(`Big Segment store status query returned error: ${err}`); newStatus = { available: false, stale: false }; } const lastStatus = this.statusProvider.getStatus(); if (!lastStatus || lastStatus.available !== newStatus.available || lastStatus.stale !== newStatus.stale) { (_c = this._logger) === null || _c === void 0 ? void 0 : _c.debug('Big Segment store status changed from %s to %s', JSON.stringify(lastStatus), JSON.stringify(newStatus)); this.statusProvider.setStatus(newStatus); this.statusProvider.notify(); } } _hashForUserKey(userKey) { const hasher = this._crypto.createHash('sha256'); hasher.update(userKey); if (!hasher.digest) { // This represents an error in platform implementation. throw new Error('Platform must implement digest or asyncDigest'); } return hasher.digest('base64'); } _isStale(timestamp) { return Date.now() - timestamp >= this._staleTimeMs; } } exports.default = BigSegmentsManager; //# sourceMappingURL=BigSegmentsManager.js.map