1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: separate frontend and backend applications from edge (#9863)

This commit is contained in:
Mateusz Kwasniewski 2025-04-29 15:42:47 +02:00 committed by GitHub
parent d44b7ac6c2
commit 58a01d0c47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 132 additions and 33 deletions

View File

@ -55,12 +55,21 @@ test('Apps registered should be announced', async () => {
description: faker.company.catchPhrase(),
color: faker.internet.color(),
};
await clientInstanceService.registerClient(clientRegistration, '127.0.0.1');
await clientInstanceService.registerClient(differentClient, '127.0.0.1');
await clientInstanceService.registerBackendClient(
clientRegistration,
'127.0.0.1',
);
await clientInstanceService.registerBackendClient(
differentClient,
'127.0.0.1',
);
await clientInstanceService.bulkAdd(); // in prod called by a SchedulerService
const first = await stores.clientApplicationsStore.getUnannounced();
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
const second = await stores.clientApplicationsStore.getUnannounced();
expect(second.length).toBe(0);

View File

@ -41,10 +41,10 @@ test('Multiple registrations of same appname and instanceid within same time per
started: new Date(),
interval: 10,
};
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
@ -98,12 +98,12 @@ test('Multiple unique clients causes multiple registrations', async () => {
started: new Date(),
interval: 10,
};
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client2, '127.0.0.1');
await clientMetrics.registerClient(client2, '127.0.0.1');
await clientMetrics.registerClient(client2, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client2, '127.0.0.1');
await clientMetrics.registerBackendClient(client2, '127.0.0.1');
await clientMetrics.registerBackendClient(client2, '127.0.0.1');
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(),
interval: 10,
};
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.registerBackendClient(client1, '127.0.0.1');
await clientMetrics.bulkAdd(); // in prod called by a SchedulerService

View File

@ -114,7 +114,7 @@ export default class ClientInstanceService {
this.seenClients[this.clientKey(data)] = data;
}
public async registerClient(
public async registerBackendClient(
data: PartialSome<IClientApp, 'instanceId'>,
clientIp: string,
): Promise<void> {

View File

@ -16,6 +16,7 @@ import dbInit, {
import { startOfHour } from 'date-fns';
import { ApiTokenType } from '../../../types/models/api-token';
import type TestAgent from 'supertest/lib/agent';
import type { BulkRegistrationSchema } from '../../../openapi';
let db: ITestDb;
let config: IUnleashConfig;
@ -41,7 +42,13 @@ let services: IUnleashServices;
let destroy: () => Promise<void>;
beforeAll(async () => {
const setup = await getSetup();
const setup = await getSetup({
experimental: {
flags: {
registerFrontendClient: true,
},
},
});
request = setup.request;
stores = setup.stores;
destroy = setup.destroy;
@ -274,6 +281,67 @@ test('should return 204 if metrics are disabled by feature flag', async () => {
});
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 () => {
const now = new Date();

View File

@ -143,12 +143,31 @@ export default class ClientMetricsController extends Controller {
try {
const promises: Promise<void>[] = [];
for (const app of applications) {
promises.push(
this.clientInstanceService.registerClient(
app,
clientIp,
),
);
if (
app.sdkType === 'frontend' &&
typeof app.sdkVersion === 'string'
) {
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) {
const data: IClientMetricsEnv[] =

View File

@ -94,7 +94,7 @@ export default class RegisterController extends Controller {
data.environment = this.resolveEnvironment(user, data);
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();
}
}

View File

@ -84,10 +84,7 @@ export const clientRegisterSchema = joi
appName: joi.string().required(),
instanceId: joi.string().empty(['', null]).default('default'),
sdkVersion: joi.string().optional(),
strategies: joi
.array()
.required()
.items(joi.string(), joi.any().strip()),
strategies: joi.array().items(joi.string(), joi.any().strip()),
started: joi.date().required(),
interval: joi.number().required(),
environment: joi.string().optional(),

View File

@ -70,6 +70,12 @@ export const bulkRegistrationSchema = {
example: 'unleash-client-java:8.0.0',
type: 'string',
},
sdkType: {
description: 'The sdk type',
example: 'backend',
type: 'string',
enum: ['frontend', 'backend'],
},
},
components: {
schemas: {

View File

@ -466,7 +466,7 @@ export interface IFrontendClientApp {
sdkVersion: string;
sdkType: 'frontend';
environment: string;
projects: string[];
projects?: string[];
createdBy?: string;
}