From 73f355984de468ee83c4271d24e9681dd05391aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gast=C3=B3n=20Fournier?= Date: Tue, 15 Oct 2024 13:15:51 +0200 Subject: [PATCH] Remove jitter and migrate tasks to execute immediately --- src/lib/metrics-gauge.ts | 40 ++++++++++++++++++++++++++++++---------- src/lib/metrics.ts | 19 ++++++++++--------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/lib/metrics-gauge.ts b/src/lib/metrics-gauge.ts index 87a0269ed4..880b26259b 100644 --- a/src/lib/metrics-gauge.ts +++ b/src/lib/metrics-gauge.ts @@ -1,11 +1,18 @@ +import type { Logger } from './logger'; +import type { IUnleashConfig } from './types'; import { createGauge, type Gauge } from './util/metrics'; type RestrictedRecord = Record; type Query = () => Promise; -type MapResult = (result: R) => { - count: number; - labels: RestrictedRecord['labelNames']>; -}; +type MapResult = (result: R) => + | { + count: number; + labels: RestrictedRecord['labelNames']>; + } + | { + count: number; + labels: RestrictedRecord['labelNames']>; + }[]; type GaugeDefinition = { name: string; @@ -19,18 +26,31 @@ type Task = () => Promise; export class DbMetricsMonitor { private tasks: Set = new Set(); private gauges: Map> = new Map(); + private logger: Logger; - constructor() {} + constructor(config: IUnleashConfig) { + this.logger = config.getLogger('gauge-metrics'); + } + + private asArray(value: T | T[]): T[] { + return Array.isArray(value) ? value : [value]; + } registerGaugeDbMetric(definition: GaugeDefinition): Task { const gauge = createGauge(definition); this.gauges.set(definition.name, gauge); const task = async () => { - const result = await definition.query(); - if (result !== null && result !== undefined) { - const { count, labels } = definition.map(result); - gauge.reset(); - gauge.labels(labels).set(count); + try { + const result = await definition.query(); + if (result !== null && result !== undefined) { + const results = this.asArray(definition.map(result)); + gauge.reset(); + for (const r of results) { + gauge.labels(r.labels).set(r.count); + } + } + } catch (e) { + this.logger.warn(`Failed to refresh ${definition.name}`, e); } }; this.tasks.add(task); diff --git a/src/lib/metrics.ts b/src/lib/metrics.ts index d276e61e44..75b7c966ed 100644 --- a/src/lib/metrics.ts +++ b/src/lib/metrics.ts @@ -57,7 +57,7 @@ export default class MetricsMonitor { const { eventStore, environmentStore } = stores; const { flagResolver } = config; - const dbMetrics = new DbMetricsMonitor(); + const dbMetrics = new DbMetricsMonitor(config); const cachedEnvironments: () => Promise = memoizee( async () => environmentStore.getAll(), @@ -260,11 +260,18 @@ export default class MetricsMonitor { help: 'Number of strategies', }); - const clientAppsTotal = createGauge({ + // execute immediately to get initial values + await dbMetrics.registerGaugeDbMetric({ name: 'client_apps_total', help: 'Number of registered client apps aggregated by range by last seen', labelNames: ['range'], - }); + query: () => instanceStatsService.getLabeledAppCounts(), + map: (result) => + Object.entries(result).map(([range, count]) => ({ + count, + labels: { range }, + })), + })(); const samlEnabled = createGauge({ name: 'saml_enabled', @@ -628,11 +635,6 @@ export default class MetricsMonitor { oidcEnabled.reset(); oidcEnabled.set(stats.OIDCenabled ? 1 : 0); - clientAppsTotal.reset(); - stats.clientApps.forEach(({ range, count }) => - clientAppsTotal.labels({ range }).set(count), - ); - rateLimits.reset(); rateLimits .labels({ @@ -695,7 +697,6 @@ export default class MetricsMonitor { collectStaticCounters.bind(this), hoursToMilliseconds(2), 'collectStaticCounters', - 0, // no jitter ); eventBus.on(