UNPKG

unleash-server

Version:

Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.

104 lines 4.03 kB
import HyperLogLog from 'hyperloglog-lite'; import { SDK_CONNECTION_ID_RECEIVED } from '../../metric-events.js'; import { REGISTERS_EXPONENT } from './hyperloglog-config.js'; export class UniqueConnectionService { constructor({ uniqueConnectionStore, }, config) { this.hll = HyperLogLog(REGISTERS_EXPONENT); this.backendHll = HyperLogLog(REGISTERS_EXPONENT); this.frontendHll = HyperLogLog(REGISTERS_EXPONENT); this.uniqueConnectionStore = uniqueConnectionStore; this.logger = config.getLogger('services/unique-connection-service.ts'); this.flagResolver = config.flagResolver; this.eventBus = config.eventBus; this.activeHour = new Date().getHours(); } listen() { this.eventBus.on(SDK_CONNECTION_ID_RECEIVED, this.count.bind(this)); } count({ connectionId, type, }) { if (!this.flagResolver.isEnabled('uniqueSdkTracking')) return; const value = HyperLogLog.hash(connectionId); this.hll.add(value); if (type === 'frontend') { this.frontendHll.add(value); } else if (type === 'backend') { this.backendHll.add(value); } } async sync(currentTime = new Date()) { if (!this.flagResolver.isEnabled('uniqueSdkTracking')) return; const currentHour = currentTime.getHours(); await this.syncBuckets(currentTime, 'current', 'previous'); await this.syncBuckets(currentTime, 'currentBackend', 'previousBackend'); await this.syncBuckets(currentTime, 'currentFrontend', 'previousFrontend'); if (this.activeHour !== currentHour) { this.activeHour = currentHour; } } resetHll(bucketId) { if (bucketId.toLowerCase().includes('frontend')) { this.frontendHll = HyperLogLog(REGISTERS_EXPONENT); } else if (bucketId.toLowerCase().includes('backend')) { this.backendHll = HyperLogLog(REGISTERS_EXPONENT); } else { this.hll = HyperLogLog(REGISTERS_EXPONENT); } } getHll(bucketId) { if (bucketId.toLowerCase().includes('frontend')) { return this.frontendHll; } else if (bucketId.toLowerCase().includes('backend')) { return this.backendHll; } else { return this.hll; } } async syncBuckets(currentTime, current, previous) { const currentHour = currentTime.getHours(); const currentBucket = await this.uniqueConnectionStore.get(current); if (this.activeHour !== currentHour && currentBucket) { if (currentBucket.updatedAt.getHours() < currentHour) { this.getHll(current).merge({ n: REGISTERS_EXPONENT, buckets: currentBucket.hll, }); await this.uniqueConnectionStore.insert({ hll: this.getHll(current).output().buckets, id: previous, }); } else { const previousBucket = await this.uniqueConnectionStore.get(previous); if (previousBucket) { this.getHll(current).merge({ n: REGISTERS_EXPONENT, buckets: previousBucket.hll, }); } await this.uniqueConnectionStore.insert({ hll: this.getHll(current).output().buckets, id: previous, }); } this.resetHll(current); } else if (currentBucket) { this.getHll(current).merge({ n: REGISTERS_EXPONENT, buckets: currentBucket.hll, }); } await this.uniqueConnectionStore.insert({ hll: this.getHll(current).output().buckets, id: current, }); } } //# sourceMappingURL=unique-connection-service.js.map