mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-28 17:55:15 +02:00
feat: separate frontend and backend applications from edge (#9863)
This commit is contained in:
parent
d44b7ac6c2
commit
58a01d0c47
@ -55,12 +55,21 @@ test('Apps registered should be announced', async () => {
|
|||||||
description: faker.company.catchPhrase(),
|
description: faker.company.catchPhrase(),
|
||||||
color: faker.internet.color(),
|
color: faker.internet.color(),
|
||||||
};
|
};
|
||||||
await clientInstanceService.registerClient(clientRegistration, '127.0.0.1');
|
await clientInstanceService.registerBackendClient(
|
||||||
await clientInstanceService.registerClient(differentClient, '127.0.0.1');
|
clientRegistration,
|
||||||
|
'127.0.0.1',
|
||||||
|
);
|
||||||
|
await clientInstanceService.registerBackendClient(
|
||||||
|
differentClient,
|
||||||
|
'127.0.0.1',
|
||||||
|
);
|
||||||
await clientInstanceService.bulkAdd(); // in prod called by a SchedulerService
|
await clientInstanceService.bulkAdd(); // in prod called by a SchedulerService
|
||||||
const first = await stores.clientApplicationsStore.getUnannounced();
|
const first = await stores.clientApplicationsStore.getUnannounced();
|
||||||
expect(first.length).toBe(2);
|
expect(first.length).toBe(2);
|
||||||
await clientInstanceService.registerClient(clientRegistration, '127.0.0.1');
|
await clientInstanceService.registerBackendClient(
|
||||||
|
clientRegistration,
|
||||||
|
'127.0.0.1',
|
||||||
|
);
|
||||||
await clientInstanceService.announceUnannounced(); // in prod called by a SchedulerService
|
await clientInstanceService.announceUnannounced(); // in prod called by a SchedulerService
|
||||||
const second = await stores.clientApplicationsStore.getUnannounced();
|
const second = await stores.clientApplicationsStore.getUnannounced();
|
||||||
expect(second.length).toBe(0);
|
expect(second.length).toBe(0);
|
||||||
|
@ -41,10 +41,10 @@ test('Multiple registrations of same appname and instanceid within same time per
|
|||||||
started: new Date(),
|
started: new Date(),
|
||||||
interval: 10,
|
interval: 10,
|
||||||
};
|
};
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
|
|
||||||
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
|
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
|
||||||
|
|
||||||
@ -98,12 +98,12 @@ test('Multiple unique clients causes multiple registrations', async () => {
|
|||||||
started: new Date(),
|
started: new Date(),
|
||||||
interval: 10,
|
interval: 10,
|
||||||
};
|
};
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client2, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client2, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client2, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client2, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client2, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client2, '127.0.0.1');
|
||||||
|
|
||||||
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
|
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
|
||||||
|
|
||||||
@ -141,15 +141,15 @@ test('Same client registered outside of dedup interval will be registered twice'
|
|||||||
started: new Date(),
|
started: new Date(),
|
||||||
interval: 10,
|
interval: 10,
|
||||||
};
|
};
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
|
|
||||||
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
|
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
|
||||||
|
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
await clientMetrics.registerClient(client1, '127.0.0.1');
|
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
|
||||||
|
|
||||||
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
|
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ export default class ClientInstanceService {
|
|||||||
this.seenClients[this.clientKey(data)] = data;
|
this.seenClients[this.clientKey(data)] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async registerClient(
|
public async registerBackendClient(
|
||||||
data: PartialSome<IClientApp, 'instanceId'>,
|
data: PartialSome<IClientApp, 'instanceId'>,
|
||||||
clientIp: string,
|
clientIp: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
@ -16,6 +16,7 @@ import dbInit, {
|
|||||||
import { startOfHour } from 'date-fns';
|
import { startOfHour } from 'date-fns';
|
||||||
import { ApiTokenType } from '../../../types/models/api-token';
|
import { ApiTokenType } from '../../../types/models/api-token';
|
||||||
import type TestAgent from 'supertest/lib/agent';
|
import type TestAgent from 'supertest/lib/agent';
|
||||||
|
import type { BulkRegistrationSchema } from '../../../openapi';
|
||||||
|
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let config: IUnleashConfig;
|
let config: IUnleashConfig;
|
||||||
@ -41,7 +42,13 @@ let services: IUnleashServices;
|
|||||||
let destroy: () => Promise<void>;
|
let destroy: () => Promise<void>;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const setup = await getSetup();
|
const setup = await getSetup({
|
||||||
|
experimental: {
|
||||||
|
flags: {
|
||||||
|
registerFrontendClient: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
request = setup.request;
|
request = setup.request;
|
||||||
stores = setup.stores;
|
stores = setup.stores;
|
||||||
destroy = setup.destroy;
|
destroy = setup.destroy;
|
||||||
@ -274,6 +281,67 @@ test('should return 204 if metrics are disabled by feature flag', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('bulk metrics', () => {
|
describe('bulk metrics', () => {
|
||||||
|
test('should separate frontend applications and backend applications', async () => {
|
||||||
|
const frontendApp: BulkRegistrationSchema = {
|
||||||
|
appName: 'application-name',
|
||||||
|
instanceId: 'browser',
|
||||||
|
environment: 'development',
|
||||||
|
sdkVersion: 'unleash-client-js:1.0.0',
|
||||||
|
sdkType: 'frontend',
|
||||||
|
};
|
||||||
|
const backendApp: BulkRegistrationSchema = {
|
||||||
|
appName: 'application-name',
|
||||||
|
instanceId: 'instance1234',
|
||||||
|
environment: 'development',
|
||||||
|
sdkVersion: 'unleash-client-node',
|
||||||
|
sdkType: 'backend',
|
||||||
|
started: '1952-03-11T12:00:00.000Z',
|
||||||
|
interval: 15000,
|
||||||
|
};
|
||||||
|
const defaultApp: BulkRegistrationSchema = {
|
||||||
|
appName: 'application-name',
|
||||||
|
instanceId: 'instance5678',
|
||||||
|
environment: 'development',
|
||||||
|
sdkVersion: 'unleash-client-java',
|
||||||
|
started: '1952-03-11T12:00:00.000Z',
|
||||||
|
interval: 15000,
|
||||||
|
};
|
||||||
|
await request
|
||||||
|
.post('/api/client/metrics/bulk')
|
||||||
|
.send({
|
||||||
|
applications: [frontendApp, backendApp, defaultApp],
|
||||||
|
metrics: [],
|
||||||
|
})
|
||||||
|
.expect(202);
|
||||||
|
|
||||||
|
await services.clientInstanceService.bulkAdd();
|
||||||
|
const app =
|
||||||
|
await services.clientInstanceService.getApplication(
|
||||||
|
'application-name',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(app).toMatchObject({
|
||||||
|
appName: 'application-name',
|
||||||
|
instances: [
|
||||||
|
{
|
||||||
|
instanceId: 'browser',
|
||||||
|
sdkVersion: 'unleash-client-js:1.0.0',
|
||||||
|
environment: 'development',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instanceId: 'instance1234',
|
||||||
|
sdkVersion: 'unleash-client-node',
|
||||||
|
environment: 'development',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instanceId: 'instance5678',
|
||||||
|
sdkVersion: 'unleash-client-java',
|
||||||
|
environment: 'development',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('filters out metrics for environments we do not have access for. No auth setup so we can only access default env', async () => {
|
test('filters out metrics for environments we do not have access for. No auth setup so we can only access default env', async () => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
|
@ -143,12 +143,31 @@ export default class ClientMetricsController extends Controller {
|
|||||||
try {
|
try {
|
||||||
const promises: Promise<void>[] = [];
|
const promises: Promise<void>[] = [];
|
||||||
for (const app of applications) {
|
for (const app of applications) {
|
||||||
promises.push(
|
if (
|
||||||
this.clientInstanceService.registerClient(
|
app.sdkType === 'frontend' &&
|
||||||
app,
|
typeof app.sdkVersion === 'string'
|
||||||
clientIp,
|
) {
|
||||||
),
|
if (
|
||||||
);
|
this.flagResolver.isEnabled(
|
||||||
|
'registerFrontendClient',
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.clientInstanceService.registerFrontendClient({
|
||||||
|
appName: app.appName,
|
||||||
|
instanceId: app.instanceId,
|
||||||
|
environment: app.environment,
|
||||||
|
sdkType: app.sdkType,
|
||||||
|
sdkVersion: app.sdkVersion,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
promises.push(
|
||||||
|
this.clientInstanceService.registerBackendClient(
|
||||||
|
app,
|
||||||
|
clientIp,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (metrics && metrics.length > 0) {
|
if (metrics && metrics.length > 0) {
|
||||||
const data: IClientMetricsEnv[] =
|
const data: IClientMetricsEnv[] =
|
||||||
|
@ -94,7 +94,7 @@ export default class RegisterController extends Controller {
|
|||||||
data.environment = this.resolveEnvironment(user, data);
|
data.environment = this.resolveEnvironment(user, data);
|
||||||
data.projects = this.resolveProject(user);
|
data.projects = this.resolveProject(user);
|
||||||
|
|
||||||
await this.clientInstanceService.registerClient(data, clientIp);
|
await this.clientInstanceService.registerBackendClient(data, clientIp);
|
||||||
res.header('X-Unleash-Version', version).status(202).end();
|
res.header('X-Unleash-Version', version).status(202).end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,10 +84,7 @@ export const clientRegisterSchema = joi
|
|||||||
appName: joi.string().required(),
|
appName: joi.string().required(),
|
||||||
instanceId: joi.string().empty(['', null]).default('default'),
|
instanceId: joi.string().empty(['', null]).default('default'),
|
||||||
sdkVersion: joi.string().optional(),
|
sdkVersion: joi.string().optional(),
|
||||||
strategies: joi
|
strategies: joi.array().items(joi.string(), joi.any().strip()),
|
||||||
.array()
|
|
||||||
.required()
|
|
||||||
.items(joi.string(), joi.any().strip()),
|
|
||||||
started: joi.date().required(),
|
started: joi.date().required(),
|
||||||
interval: joi.number().required(),
|
interval: joi.number().required(),
|
||||||
environment: joi.string().optional(),
|
environment: joi.string().optional(),
|
||||||
|
@ -70,6 +70,12 @@ export const bulkRegistrationSchema = {
|
|||||||
example: 'unleash-client-java:8.0.0',
|
example: 'unleash-client-java:8.0.0',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
|
sdkType: {
|
||||||
|
description: 'The sdk type',
|
||||||
|
example: 'backend',
|
||||||
|
type: 'string',
|
||||||
|
enum: ['frontend', 'backend'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
schemas: {
|
schemas: {
|
||||||
|
@ -466,7 +466,7 @@ export interface IFrontendClientApp {
|
|||||||
sdkVersion: string;
|
sdkVersion: string;
|
||||||
sdkType: 'frontend';
|
sdkType: 'frontend';
|
||||||
environment: string;
|
environment: string;
|
||||||
projects: string[];
|
projects?: string[];
|
||||||
createdBy?: string;
|
createdBy?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user