1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-10 01:16:39 +02:00

fix: rename metrics-service to client-instance service

This commit is contained in:
Ivar Conradi Østhus 2021-12-09 21:25:06 +01:00
parent 4a9939ccb1
commit 9f13b801eb
23 changed files with 65 additions and 330 deletions

View File

@ -26,7 +26,7 @@ function getSetup() {
request: supertest(app),
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -22,7 +22,7 @@ function getSetup() {
request: supertest(app),
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -20,7 +20,7 @@ function getSetup() {
perms,
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -4,23 +4,23 @@ import { UPDATE_APPLICATION } from '../../types/permissions';
import { IUnleashConfig } from '../../types/option';
import { IUnleashServices } from '../../types/services';
import { Logger } from '../../logger';
import ClientMetricsService from '../../services/client-metrics';
import ClientInstanceService from '../../services/client-metrics/client-instance-service';
class MetricsController extends Controller {
private logger: Logger;
private metrics: ClientMetricsService;
private clientInstanceService: ClientInstanceService;
constructor(
config: IUnleashConfig,
{
clientMetricsService,
}: Pick<IUnleashServices, 'clientMetricsService'>,
clientInstanceService,
}: Pick<IUnleashServices, 'clientInstanceService'>,
) {
super(config);
this.logger = config.getLogger('/admin-api/metrics.ts');
this.metrics = clientMetricsService;
this.clientInstanceService = clientInstanceService;
// deprecated routes
this.get('/seen-toggles', this.deprecated);
@ -54,13 +54,13 @@ class MetricsController extends Controller {
async deleteApplication(req: Request, res: Response): Promise<void> {
const { appName } = req.params;
await this.metrics.deleteApplication(appName);
await this.clientInstanceService.deleteApplication(appName);
res.status(200).end();
}
async createApplication(req: Request, res: Response): Promise<void> {
const input = { ...req.body, appName: req.params.appName };
await this.metrics.createApplication(input);
await this.clientInstanceService.createApplication(input);
res.status(202).end();
}
@ -68,14 +68,18 @@ class MetricsController extends Controller {
const query = req.query.strategyName
? { strategyName: req.query.strategyName as string }
: {};
const applications = await this.metrics.getApplications(query);
const applications = await this.clientInstanceService.getApplications(
query,
);
res.json({ applications });
}
async getApplication(req: Request, res: Response): Promise<void> {
const { appName } = req.params;
const appDetails = await this.metrics.getApplication(appName);
const appDetails = await this.clientInstanceService.getApplication(
appName,
);
res.json(appDetails);
}
}

View File

@ -20,7 +20,7 @@ function getSetup() {
destroy = () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
};

View File

@ -23,7 +23,7 @@ function getSetup() {
request: supertest(app),
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -20,6 +20,6 @@ test('should enable prometheus', async () => {
.expect('Content-Type', /text/)
.expect(200);
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
});

View File

@ -24,7 +24,7 @@ function getSetup() {
request: supertest(app),
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -19,7 +19,7 @@ function getSetup(opts?: IUnleashOptions) {
stores,
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -2,7 +2,7 @@ import { Response } from 'express';
import Controller from '../controller';
import { IUnleashServices } from '../../types';
import { IUnleashConfig } from '../../types/option';
import ClientMetricsService from '../../services/client-metrics';
import ClientInstanceService from '../../services/client-metrics/client-instance-service';
import { Logger } from '../../logger';
import { IAuthRequest } from '../unleash-types';
import ApiUser from '../../types/api-user';
@ -15,17 +15,17 @@ import { NONE } from '../../types/permissions';
export default class ClientMetricsController extends Controller {
logger: Logger;
metrics: ClientMetricsService;
clientInstanceService: ClientInstanceService;
metricsV2: ClientMetricsServiceV2;
constructor(
{
clientMetricsService,
clientInstanceService,
clientMetricsServiceV2,
}: Pick<
IUnleashServices,
'clientMetricsService' | 'clientMetricsServiceV2'
'clientInstanceService' | 'clientMetricsServiceV2'
>,
config: IUnleashConfig,
) {
@ -33,7 +33,7 @@ export default class ClientMetricsController extends Controller {
const { getLogger } = config;
this.logger = getLogger('/api/client/metrics');
this.metrics = clientMetricsService;
this.clientInstanceService = clientInstanceService;
this.metricsV2 = clientMetricsServiceV2;
this.post('/', this.registerMetrics, NONE);
@ -53,7 +53,7 @@ export default class ClientMetricsController extends Controller {
async registerMetrics(req: IAuthRequest, res: Response): Promise<void> {
const { body: data, ip: clientIp, user } = req;
data.environment = this.resolveEnvironment(user, data);
await this.metrics.registerClientMetrics(data, clientIp);
await this.clientInstanceService.registerInstance(data, clientIp);
await this.metricsV2.registerClientMetrics(data, clientIp);

View File

@ -16,7 +16,7 @@ function getSetup() {
stores,
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -3,7 +3,7 @@ import Controller from '../controller';
import { IUnleashServices } from '../../types';
import { IUnleashConfig } from '../../types/option';
import { Logger } from '../../logger';
import ClientMetricsService from '../../services/client-metrics';
import ClientInstanceService from '../../services/client-metrics/client-instance-service';
import { IAuthRequest, User } from '../../server-impl';
import { IClientApp } from '../../types/model';
import ApiUser from '../../types/api-user';
@ -13,17 +13,17 @@ import { NONE } from '../../types/permissions';
export default class RegisterController extends Controller {
logger: Logger;
metrics: ClientMetricsService;
metrics: ClientInstanceService;
constructor(
{
clientMetricsService,
}: Pick<IUnleashServices, 'clientMetricsService'>,
clientInstanceService,
}: Pick<IUnleashServices, 'clientInstanceService'>,
config: IUnleashConfig,
) {
super(config);
this.logger = config.getLogger('/api/client/register');
this.metrics = clientMetricsService;
this.metrics = clientInstanceService;
// NONE permission is not optimal here in terms of readability.
this.post('/', this.handleRegister, NONE);

View File

@ -18,7 +18,7 @@ function getSetup() {
stores,
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -18,7 +18,7 @@ function getSetup() {
request: supertest(app),
destroy: () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
},
};

View File

@ -20,7 +20,7 @@ import { minutesToMilliseconds, secondsToMilliseconds } from 'date-fns';
import EventEmitter from 'events';
import { IClientMetricsStoreV2 } from '../../types/stores/client-metrics-store-v2';
export default class ClientMetricsService {
export default class ClientInstanceService {
apps = {};
logger = null;
@ -91,7 +91,7 @@ export default class ClientMetricsService {
);
}
public async registerClientMetrics(
public async registerInstance(
data: IClientApp,
clientIp: string,
): Promise<void> {

View File

@ -1,5 +1,5 @@
import EventEmitter from 'events';
import ClientMetricsService from './index';
import ClientInstanceService from './client-instance-service';
import getLogger from '../../../test/fixtures/no-logger';
import { IClientApp } from '../../types/model';
import { secondsToMilliseconds } from 'date-fns';
@ -48,7 +48,7 @@ test('Multiple registrations of same appname and instanceid within same time per
const clientInstanceStore: any = {
bulkUpsert: bulkSpy,
};
const clientMetrics = new ClientMetricsService(
const clientMetrics = new ClientInstanceService(
{
clientMetricsStoreV2: null,
strategyStore: null,
@ -98,7 +98,7 @@ test('Multiple unique clients causes multiple registrations', async () => {
bulkUpsert: bulkSpy,
};
const clientMetrics = new ClientMetricsService(
const clientMetrics = new ClientInstanceService(
{
clientMetricsStoreV2: null,
strategyStore: null,
@ -151,7 +151,7 @@ test('Same client registered outside of dedup interval will be registered twice'
const bulkInterval = secondsToMilliseconds(2);
const clientMetrics = new ClientMetricsService(
const clientMetrics = new ClientInstanceService(
{
clientMetricsStoreV2: null,
strategyStore: null,
@ -204,7 +204,7 @@ test('No registrations during a time period will not call stores', async () => {
const clientInstanceStore: any = {
bulkUpsert: bulkSpy,
};
new ClientMetricsService(
new ClientInstanceService(
{
clientMetricsStoreV2: null,
strategyStore: null,

View File

@ -1,123 +0,0 @@
import List from './list';
function getList() {
const list = new List<number>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
return list;
}
test('should emit "evicted" events for objects leaving list', () => {
const list = getList();
const evictedList = [];
list.on('evicted', (value) => {
evictedList.push(value);
});
expect(evictedList.length === 0).toBe(true);
list.reverseRemoveUntilTrue(({ value }) => {
if (value === 4) {
return true;
}
return false;
});
expect(evictedList.length === 3).toBe(true);
list.reverseRemoveUntilTrue(() => false);
expect(evictedList.length === 7).toBe(true);
list.add(1);
list.reverseRemoveUntilTrue(() => false);
expect(evictedList.length === 8).toBe(true);
});
test('list should be able remove until given value', () => {
const list = getList();
expect(list.toArray().length === 7).toBe(true);
list.reverseRemoveUntilTrue(({ value }) => value === 4);
expect(list.toArray().length === 4).toBe(true);
list.reverseRemoveUntilTrue(({ value }) => value === 5);
expect(list.toArray().length === 3).toBe(true);
list.reverseRemoveUntilTrue(({ value }) => value === 5);
expect(list.toArray().length === 3).toBe(true);
});
test('list can be cleared and re-add entries', () => {
const list = getList();
list.add(8);
list.add(9);
expect(list.toArray().length === 9).toBe(true);
list.reverseRemoveUntilTrue(() => false);
expect(list.toArray().length === 0).toBe(true);
list.add(1);
list.add(2);
list.add(3);
expect(list.toArray().length === 3).toBe(true);
});
test('should not iterate empty list ', () => {
const list = new List();
let iterateCount = 0;
list.iterate(() => {
iterateCount++;
});
expect(iterateCount === 0).toBe(true);
});
test('should iterate', () => {
const list = getList();
let iterateCount = 0;
list.iterate(({ value }) => {
iterateCount++;
if (value === 4) {
return false;
}
return true;
});
expect(iterateCount === 4).toBe(true);
});
test('should reverse iterate', () => {
const list = getList();
let iterateCount = 0;
list.iterateReverse(({ value }) => {
iterateCount++;
if (value === 5) {
return false;
}
return true;
});
expect(iterateCount === 5).toBe(true);
});
test('should not reverse iterate empty list', () => {
const list = new List();
let iterateCount = 0;
list.iterateReverse(() => {
iterateCount++;
});
expect(iterateCount === 0).toBe(true);
});

View File

@ -1,138 +0,0 @@
/* eslint-disable no-param-reassign */
/* eslint-disable max-classes-per-file */
import { EventEmitter } from 'events';
class Node<T> {
value: T | null;
prev: Node<T> | null;
next: Node<T> | null;
constructor(value: T) {
this.value = value;
this.next = null;
}
link(next: Node<T>) {
this.next = next;
next.prev = this;
return this;
}
}
type IteratorFn<T, U = unknown> = (cursor: Node<T>) => U;
export default class List<T> extends EventEmitter {
private start: Node<T> | null;
private tail: Node<T> | null;
constructor() {
super();
this.start = null;
this.tail = null;
}
add(obj: T): Node<T> {
const node = new Node(obj);
if (this.start) {
this.start = node.link(this.start);
} else {
this.start = node;
this.tail = node;
}
return node;
}
iterate(fn: IteratorFn<T>): void {
if (!this.start) {
return;
}
let cursor = this.start;
while (cursor) {
const result = fn(cursor);
if (result === false) {
cursor = null;
} else {
cursor = cursor.next;
}
}
}
iterateReverse(fn: IteratorFn<T>): void {
if (!this.tail) {
return;
}
let cursor = this.tail;
while (cursor) {
const result = fn(cursor);
if (result === false) {
cursor = null;
} else {
cursor = cursor.prev;
}
}
}
reverseRemoveUntilTrue(fn: IteratorFn<T, boolean>): void {
if (!this.tail) {
return;
}
let cursor = this.tail;
while (cursor) {
const result = fn(cursor);
if (result === false && cursor === this.start) {
// whole list is removed
this.emit('evicted', cursor.value);
this.start = null;
this.tail = null;
// stop iteration
cursor = null;
} else if (result === true) {
// when TRUE, set match as new tail
if (cursor !== this.tail) {
this.tail = cursor;
cursor.next = null;
}
// stop iteration
cursor = null;
} else {
// evicted
this.emit('evicted', cursor.value);
// iterate to next
cursor = cursor.prev;
}
}
}
toArray(): T[] {
const result = [];
if (this.start) {
let cursor = this.start;
while (cursor) {
result.push(cursor.value);
cursor = cursor.next;
}
}
return result;
}
// toArrayReverse () {
// const result = [];
// if (this.tail) {
// let cursor = this.tail;
// while (cursor) {
// result.push(cursor.value);
// cursor = cursor.prev;
// }
// }
// return result;
// }
}

View File

@ -7,7 +7,7 @@ import HealthService from './health-service';
import ProjectService from './project-service';
import StateService from './state-service';
import ClientMetricsService from './client-metrics';
import ClientInstanceService from './client-metrics/client-instance-service';
import ClientMetricsServiceV2 from './client-metrics/client-metrics-service-v2';
import TagTypeService from './tag-type-service';
import TagService from './tag-service';
@ -35,7 +35,7 @@ export const createServices = (
): IUnleashServices => {
const accessService = new AccessService(stores, config);
const apiTokenService = new ApiTokenService(stores, config);
const clientMetricsService = new ClientMetricsService(stores, config);
const clientInstanceService = new ClientInstanceService(stores, config);
const clientMetricsServiceV2 = new ClientMetricsServiceV2(stores, config);
const contextService = new ContextService(stores, config);
const emailService = new EmailService(config.email, config.getLogger);
@ -87,7 +87,7 @@ export const createServices = (
strategyService,
tagTypeService,
tagService,
clientMetricsService,
clientInstanceService,
clientMetricsServiceV2,
contextService,
versionService,

View File

@ -5,7 +5,7 @@ import StateService from '../services/state-service';
import StrategyService from '../services/strategy-service';
import TagTypeService from '../services/tag-type-service';
import TagService from '../services/tag-service';
import ClientMetricsService from '../services/client-metrics';
import ClientInstanceService from '../services/client-metrics/client-instance-service';
import ContextService from '../services/context-service';
import VersionService from '../services/version-service';
import { ApiTokenService } from '../services/api-token-service';
@ -29,7 +29,7 @@ export interface IUnleashServices {
accessService: AccessService;
addonService: AddonService;
apiTokenService: ApiTokenService;
clientMetricsService: ClientMetricsService;
clientInstanceService: ClientInstanceService;
clientMetricsServiceV2: ClientMetricsServiceV2;
contextService: ContextService;
emailService: EmailService;

View File

@ -1,10 +1,9 @@
import dbInit from '../../helpers/database-init';
import { setupApp } from '../../helpers/test-helper';
import dbInit, { ITestDb } from '../../helpers/database-init';
import { IUnleashTest, setupApp } from '../../helpers/test-helper';
import getLogger from '../../../fixtures/no-logger';
import { parseISO } from 'date-fns';
let app;
let db;
let app: IUnleashTest;
let db: ITestDb;
beforeAll(async () => {
db = await dbInit('metrics_serial', getLogger);
@ -12,45 +11,38 @@ beforeAll(async () => {
});
beforeEach(async () => {
await app.services.clientMetricsService.createApplication({
await app.services.clientInstanceService.createApplication({
appName: 'demo-app-1',
strategies: ['default'],
//@ts-ignore
announced: true,
});
await app.services.clientMetricsService.createApplication({
await app.services.clientInstanceService.createApplication({
appName: 'demo-app-2',
strategies: ['default', 'extra'],
description: 'hello',
//@ts-ignore
announced: true,
});
await app.services.clientMetricsService.createApplication({
await app.services.clientInstanceService.createApplication({
appName: 'deletable-app',
strategies: ['default'],
description: 'Some desc',
//@ts-ignore
announced: true,
});
const clientStartedDate = parseISO('2018-01-15T14:35:38.494Z');
await db.stores.clientInstanceStore.insert({
appName: 'demo-app-1',
instanceId: 'test-1',
strategies: ['default'],
started: clientStartedDate,
interval: 10,
});
await db.stores.clientInstanceStore.insert({
appName: 'demo-seed-2',
instanceId: 'test-2',
strategies: ['default'],
started: clientStartedDate,
interval: 10,
});
await db.stores.clientInstanceStore.insert({
appName: 'deletable-app',
instanceId: 'inst-1',
strategies: ['default'],
started: clientStartedDate,
interval: 10,
});
});

View File

@ -43,7 +43,7 @@ function createApp(
const destroy = async () => {
services.versionService.destroy();
services.clientMetricsService.destroy();
services.clientInstanceService.destroy();
services.apiTokenService.destroy();
};

View File

@ -1,4 +1,4 @@
import ClientMetricsService from '../../../lib/services/client-metrics';
import ClientInstanceService from '../../../lib/services/client-metrics/client-instance-service';
import { IClientApp } from '../../../lib/types/model';
import { secondsToMilliseconds } from 'date-fns';
import EventEmitter from 'events';
@ -10,7 +10,7 @@ const { APPLICATION_CREATED } = require('../../../lib/types/events');
let stores;
let db;
let clientMetricsService;
let clientInstanceService;
beforeAll(async () => {
db = await dbInit('client_metrics_service_serial', getLogger);
@ -20,7 +20,7 @@ beforeAll(async () => {
const bulkInterval = secondsToMilliseconds(0.5);
const announcementInterval = secondsToMilliseconds(2);
clientMetricsService = new ClientMetricsService(
clientInstanceService = new ClientInstanceService(
stores,
{ getLogger, eventBus },
bulkInterval,
@ -29,7 +29,7 @@ beforeAll(async () => {
});
afterAll(async () => {
await clientMetricsService.destroy();
await clientInstanceService.destroy();
await db.destroy();
});
test('Apps registered should be announced', async () => {
@ -54,12 +54,12 @@ test('Apps registered should be announced', async () => {
description: faker.company.catchPhrase(),
color: faker.internet.color(),
};
await clientMetricsService.registerClient(clientRegistration, '127.0.0.1');
await clientMetricsService.registerClient(differentClient, '127.0.0.1');
await clientInstanceService.registerClient(clientRegistration, '127.0.0.1');
await clientInstanceService.registerClient(differentClient, '127.0.0.1');
await new Promise((res) => setTimeout(res, 1200));
const first = await stores.clientApplicationsStore.getUnannounced();
expect(first.length).toBe(2);
await clientMetricsService.registerClient(clientRegistration, '127.0.0.1');
await clientInstanceService.registerClient(clientRegistration, '127.0.0.1');
await new Promise((res) => setTimeout(res, secondsToMilliseconds(2)));
const second = await stores.clientApplicationsStore.getUnannounced();
expect(second.length).toBe(0);