mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: start monitoring total time to update cache (#6517)
This commit is contained in:
parent
1d526e707b
commit
2a57acca41
@ -16,7 +16,7 @@ import {
|
||||
import { validateOrigins } from '../../util';
|
||||
import { BadDataError, InvalidTokenError } from '../../error';
|
||||
import {
|
||||
OPERATION_TIME,
|
||||
FUNCTION_TIME,
|
||||
FRONTEND_API_REPOSITORY_CREATED,
|
||||
PROXY_REPOSITORY_CREATED,
|
||||
} from '../../metric-events';
|
||||
@ -77,9 +77,10 @@ export class FrontendApiService {
|
||||
this.services = services;
|
||||
this.globalFrontendApiCache = globalFrontendApiCache;
|
||||
|
||||
this.timer = (operationId) =>
|
||||
metricsHelper.wrapTimer(config.eventBus, OPERATION_TIME, {
|
||||
operationId,
|
||||
this.timer = (functionName) =>
|
||||
metricsHelper.wrapTimer(config.eventBus, FUNCTION_TIME, {
|
||||
className: 'FrontendApiService',
|
||||
functionName,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,11 @@ const createCache = (
|
||||
segment: ISegment = defaultSegment,
|
||||
features: Record<string, Record<string, IFeatureToggleClient>> = {},
|
||||
) => {
|
||||
const config = { getLogger: noLogger, flagResolver: alwaysOnFlagResolver };
|
||||
const config = {
|
||||
getLogger: noLogger,
|
||||
flagResolver: alwaysOnFlagResolver,
|
||||
eventBus: <any>{ emit: jest.fn() },
|
||||
};
|
||||
const segmentReadModel = new FakeSegmentReadModel([segment as ISegment]);
|
||||
const clientFeatureToggleReadModel = new FakeClientFeatureToggleReadModel(
|
||||
features,
|
||||
|
@ -15,8 +15,10 @@ import { ALL_ENVS } from '../../util/constants';
|
||||
import { Logger } from '../../logger';
|
||||
import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service';
|
||||
import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type';
|
||||
import metricsHelper from '../../util/metrics-helper';
|
||||
import { FUNCTION_TIME } from '../../metric-events';
|
||||
|
||||
type Config = Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>;
|
||||
type Config = Pick<IUnleashConfig, 'getLogger' | 'flagResolver' | 'eventBus'>;
|
||||
|
||||
type FrontendApiFeatureCache = Record<string, Record<string, FeatureInterface>>;
|
||||
|
||||
@ -39,6 +41,8 @@ export class GlobalFrontendApiCache extends EventEmitter {
|
||||
|
||||
private status: GlobalFrontendApiCacheState = 'starting';
|
||||
|
||||
private timer: Function;
|
||||
|
||||
constructor(
|
||||
config: Config,
|
||||
segmentReadModel: ISegmentReadModel,
|
||||
@ -52,6 +56,12 @@ export class GlobalFrontendApiCache extends EventEmitter {
|
||||
this.configurationRevisionService = configurationRevisionService;
|
||||
this.segmentReadModel = segmentReadModel;
|
||||
this.onUpdateRevisionEvent = this.onUpdateRevisionEvent.bind(this);
|
||||
this.timer = (functionName) =>
|
||||
metricsHelper.wrapTimer(config.eventBus, FUNCTION_TIME, {
|
||||
className: 'GlobalFrontendApiCache',
|
||||
functionName,
|
||||
});
|
||||
|
||||
this.refreshData();
|
||||
this.configurationRevisionService.on(
|
||||
UPDATE_REVISION,
|
||||
@ -103,6 +113,7 @@ export class GlobalFrontendApiCache extends EventEmitter {
|
||||
// TODO: also consider not fetching disabled features, because those are not returned by frontend API
|
||||
private async refreshData() {
|
||||
try {
|
||||
const stopTimer = this.timer('refreshData');
|
||||
this.featuresByEnvironment = await this.getAllFeatures();
|
||||
this.segments = await this.getAllSegments();
|
||||
if (this.status === 'starting') {
|
||||
@ -112,6 +123,7 @@ export class GlobalFrontendApiCache extends EventEmitter {
|
||||
this.status = 'updated';
|
||||
this.emit('updated');
|
||||
}
|
||||
stopTimer();
|
||||
} catch (e) {
|
||||
this.logger.error('Cannot load data for token', e);
|
||||
}
|
||||
|
@ -17,7 +17,11 @@ import { Logger } from '../../logger';
|
||||
import ConfigurationRevisionService, {
|
||||
UPDATE_REVISION,
|
||||
} from '../feature-toggle/configuration-revision-service';
|
||||
import { PROXY_FEATURES_FOR_TOKEN_TIME } from '../../metric-events';
|
||||
import {
|
||||
FUNCTION_TIME,
|
||||
PROXY_FEATURES_FOR_TOKEN_TIME,
|
||||
} from '../../metric-events';
|
||||
import metricsHelper from '../../util/metrics-helper';
|
||||
|
||||
type Config = Pick<IUnleashConfig, 'getLogger' | 'frontendApi' | 'eventBus'>;
|
||||
|
||||
@ -55,6 +59,8 @@ export class ProxyRepository
|
||||
|
||||
private running: boolean;
|
||||
|
||||
private methodTimer: Function;
|
||||
|
||||
constructor(
|
||||
config: Config,
|
||||
stores: Stores,
|
||||
@ -71,6 +77,12 @@ export class ProxyRepository
|
||||
this.token = token;
|
||||
this.onUpdateRevisionEvent = this.onUpdateRevisionEvent.bind(this);
|
||||
this.interval = config.frontendApi.refreshIntervalInMs;
|
||||
|
||||
this.methodTimer = (functionName) =>
|
||||
metricsHelper.wrapTimer(config.eventBus, FUNCTION_TIME, {
|
||||
className: 'ProxyRepository',
|
||||
functionName,
|
||||
});
|
||||
}
|
||||
|
||||
getTogglesWithSegmentData(): EnhancedFeatureInterface[] {
|
||||
@ -135,8 +147,10 @@ export class ProxyRepository
|
||||
|
||||
private async loadDataForToken() {
|
||||
try {
|
||||
const stopTimer = this.methodTimer('loadDataForToken');
|
||||
this.features = await this.featuresForToken();
|
||||
this.segments = await this.segmentsForToken();
|
||||
stopTimer();
|
||||
} catch (e) {
|
||||
this.logger.error('Cannot load data for token', e);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
const REQUEST_TIME = 'request_time';
|
||||
const DB_TIME = 'db_time';
|
||||
const OPERATION_TIME = 'operation_time';
|
||||
const FUNCTION_TIME = 'function_time';
|
||||
const SCHEDULER_JOB_TIME = 'scheduler_job_time';
|
||||
const FEATURES_CREATED_BY_PROCESSED = 'features_created_by_processed';
|
||||
const EVENTS_CREATED_BY_PROCESSED = 'events_created_by_processed';
|
||||
@ -12,7 +12,7 @@ export {
|
||||
REQUEST_TIME,
|
||||
DB_TIME,
|
||||
SCHEDULER_JOB_TIME,
|
||||
OPERATION_TIME,
|
||||
FUNCTION_TIME,
|
||||
FEATURES_CREATED_BY_PROCESSED,
|
||||
EVENTS_CREATED_BY_PROCESSED,
|
||||
FRONTEND_API_REPOSITORY_CREATED,
|
||||
|
@ -2,7 +2,7 @@ import { register } from 'prom-client';
|
||||
import EventEmitter from 'events';
|
||||
import { IEventStore } from './types/stores/event-store';
|
||||
import { createTestConfig } from '../test/config/test-config';
|
||||
import { DB_TIME, OPERATION_TIME, REQUEST_TIME } from './metric-events';
|
||||
import { DB_TIME, FUNCTION_TIME, REQUEST_TIME } from './metric-events';
|
||||
import {
|
||||
CLIENT_METRICS,
|
||||
CLIENT_REGISTER,
|
||||
@ -172,15 +172,16 @@ test('should collect metrics for db query timings', async () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('should collect metrics for operation timings', async () => {
|
||||
eventBus.emit(OPERATION_TIME, {
|
||||
operationId: 'getToggles',
|
||||
test('should collect metrics for function timings', async () => {
|
||||
eventBus.emit(FUNCTION_TIME, {
|
||||
functionName: 'getToggles',
|
||||
className: 'ToggleService',
|
||||
time: 0.1337,
|
||||
});
|
||||
|
||||
const metrics = await prometheusRegister.metrics();
|
||||
expect(metrics).toMatch(
|
||||
/operation_duration_seconds\{quantile="0\.99",operationId="getToggles"\} 0.1337/,
|
||||
/function_duration_seconds\{quantile="0\.99",functionName="getToggles",className="ToggleService"\} 0.1337/,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -85,10 +85,10 @@ export default class MetricsMonitor {
|
||||
maxAgeSeconds: 600,
|
||||
ageBuckets: 5,
|
||||
});
|
||||
const operationDuration = createSummary({
|
||||
name: 'operation_duration_seconds',
|
||||
help: 'Operation duration time',
|
||||
labelNames: ['operationId'],
|
||||
const functionDuration = createSummary({
|
||||
name: 'function_duration_seconds',
|
||||
help: 'Function duration time',
|
||||
labelNames: ['functionName', 'className'],
|
||||
percentiles: [0.1, 0.5, 0.9, 0.95, 0.99],
|
||||
maxAgeSeconds: 600,
|
||||
ageBuckets: 5,
|
||||
@ -413,9 +413,14 @@ export default class MetricsMonitor {
|
||||
schedulerDuration.labels(jobId).observe(time);
|
||||
});
|
||||
|
||||
eventBus.on(events.OPERATION_TIME, ({ operationId, time }) => {
|
||||
operationDuration.labels(operationId).observe(time);
|
||||
});
|
||||
eventBus.on(
|
||||
events.FUNCTION_TIME,
|
||||
({ functionName, className, time }) => {
|
||||
functionDuration
|
||||
.labels({ functionName, className })
|
||||
.observe(time);
|
||||
},
|
||||
);
|
||||
|
||||
eventBus.on(events.EVENTS_CREATED_BY_PROCESSED, ({ updated }) => {
|
||||
eventCreatedByMigration.inc(updated);
|
||||
|
Loading…
Reference in New Issue
Block a user