UNPKG

unleash-server

Version:

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

124 lines 4.41 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ClientMetricsStoreV2 = void 0; const notfound_error_1 = __importDefault(require("../error/notfound-error")); const date_fns_1 = require("date-fns"); const collapseHourlyMetrics_1 = require("../util/collapseHourlyMetrics"); const TABLE = 'client_metrics_env'; const fromRow = (row) => ({ featureName: row.feature_name, appName: row.app_name, environment: row.environment, timestamp: row.timestamp, yes: Number(row.yes), no: Number(row.no), }); const toRow = (metric) => ({ feature_name: metric.featureName, app_name: metric.appName, environment: metric.environment, timestamp: (0, date_fns_1.startOfHour)(metric.timestamp), yes: metric.yes, no: metric.no, }); class ClientMetricsStoreV2 { constructor(db, getLogger) { this.db = db; this.logger = getLogger('client-metrics-store-v2.js'); } async get(key) { const row = await this.db(TABLE) .where({ feature_name: key.featureName, app_name: key.appName, environment: key.environment, timestamp: (0, date_fns_1.startOfHour)(key.timestamp), }) .first(); if (row) { return fromRow(row); } throw new notfound_error_1.default(`Could not find metric`); } async getAll(query = {}) { const rows = await this.db(TABLE) .select('*') .where(query); return rows.map(fromRow); } async exists(key) { try { await this.get(key); return true; } catch (e) { return false; } } async delete(key) { return this.db(TABLE) .where({ feature_name: key.featureName, app_name: key.appName, environment: key.environment, timestamp: (0, date_fns_1.startOfHour)(key.timestamp), }) .del(); } deleteAll() { return this.db(TABLE).del(); } destroy() { // Nothing to do! } // this function will collapse metrics before sending it to the database. async batchInsertMetrics(metrics) { if (!metrics || metrics.length == 0) { return; } const rows = (0, collapseHourlyMetrics_1.collapseHourlyMetrics)(metrics).map(toRow); // Sort the rows to avoid deadlocks const sortedRows = rows.sort((a, b) => a.feature_name.localeCompare(b.feature_name) || a.app_name.localeCompare(b.app_name) || a.environment.localeCompare(b.environment)); // Consider rewriting to SQL batch! const insert = this.db(TABLE) .insert(sortedRows) .toQuery(); const query = `${insert.toString()} ON CONFLICT (feature_name, app_name, environment, timestamp) DO UPDATE SET "yes" = "client_metrics_env"."yes" + EXCLUDED.yes, "no" = "client_metrics_env"."no" + EXCLUDED.no`; await this.db.raw(query); } async getMetricsForFeatureToggle(featureName, hoursBack = 24) { const rows = await this.db(TABLE) .select('*') .where({ feature_name: featureName }) .andWhereRaw(`timestamp >= NOW() - INTERVAL '${hoursBack} hours'`); return rows.map(fromRow); } async getSeenAppsForFeatureToggle(featureName, hoursBack = 24) { return this.db(TABLE) .distinct() .where({ feature_name: featureName }) .andWhereRaw(`timestamp >= NOW() - INTERVAL '${hoursBack} hours'`) .pluck('app_name') .orderBy('app_name'); } async getSeenTogglesForApp(appName, hoursBack = 24) { return this.db(TABLE) .distinct() .where({ app_name: appName }) .andWhereRaw(`timestamp >= NOW() - INTERVAL '${hoursBack} hours'`) .pluck('feature_name') .orderBy('feature_name'); } async clearMetrics(hoursAgo) { return this.db(TABLE) .whereRaw(`timestamp <= NOW() - INTERVAL '${hoursAgo} hours'`) .del(); } } exports.ClientMetricsStoreV2 = ClientMetricsStoreV2; //# sourceMappingURL=client-metrics-store-v2.js.map