unleash-server
Version:
Unleash is an enterprise ready feature toggles service. It provides different strategies for handling feature toggles.
124 lines • 4.41 kB
JavaScript
;
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