1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-04 01:18:20 +02:00

fix: improve health rating job performance (#9761)

This commit is contained in:
Mateusz Kwasniewski 2025-04-15 14:20:26 +02:00 committed by GitHub
parent 3fd74262bb
commit 6396da3e77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 15 deletions

View File

@ -10,6 +10,9 @@ import {
calculateProjectHealth, calculateProjectHealth,
calculateProjectHealthRating, calculateProjectHealthRating,
} from '../domain/project-health/project-health'; } from '../domain/project-health/project-health';
import { batchExecute } from '../util';
import metricsHelper from '../util/metrics-helper';
import { FUNCTION_TIME } from '../metric-events';
export default class ProjectHealthService { export default class ProjectHealthService {
private logger: Logger; private logger: Logger;
@ -22,7 +25,9 @@ export default class ProjectHealthService {
private projectService: ProjectService; private projectService: ProjectService;
calculateHealthRating: (project: IProject) => Promise<number>; calculateHealthRating: (project: Pick<IProject, 'id'>) => Promise<number>;
private timer: Function;
constructor( constructor(
{ {
@ -33,7 +38,7 @@ export default class ProjectHealthService {
IUnleashStores, IUnleashStores,
'projectStore' | 'featureTypeStore' | 'featureToggleStore' 'projectStore' | 'featureTypeStore' | 'featureToggleStore'
>, >,
{ getLogger }: Pick<IUnleashConfig, 'getLogger'>, { getLogger, eventBus }: Pick<IUnleashConfig, 'getLogger' | 'eventBus'>,
projectService: ProjectService, projectService: ProjectService,
) { ) {
this.logger = getLogger('services/project-health-service.ts'); this.logger = getLogger('services/project-health-service.ts');
@ -46,6 +51,11 @@ export default class ProjectHealthService {
this.featureTypeStore, this.featureTypeStore,
this.featureToggleStore, this.featureToggleStore,
); );
this.timer = (functionName: string) =>
metricsHelper.wrapTimer(eventBus, FUNCTION_TIME, {
className: 'ProjectHealthService',
functionName,
});
} }
async getProjectHealthReport( async getProjectHealthReport(
@ -70,17 +80,21 @@ export default class ProjectHealthService {
}; };
} }
async setHealthRating(): Promise<void> { async setHealthRating(batchSize = 1): Promise<void> {
const projects = await this.projectStore.getAll(); const projects = await this.projectStore.getAll();
await Promise.all( void batchExecute(projects, batchSize, 5000, (project) =>
projects.map(async (project) => { this.setProjectHealthRating(project.id),
const newHealth = await this.calculateHealthRating(project);
await this.projectStore.updateHealth({
id: project.id,
health: newHealth,
});
}),
); );
} }
async setProjectHealthRating(projectId: string): Promise<void> {
const stopTimer = this.timer('setProjectHealthRating');
const newHealth = await this.calculateHealthRating({ id: projectId });
await this.projectStore.updateHealth({
id: projectId,
health: newHealth,
});
stopTimer();
}
} }

View File

@ -112,7 +112,7 @@ test('Health rating endpoint yields stale, potentially stale and active count on
stale: true, stale: true,
}) })
.expect(201); .expect(201);
await app.services.projectHealthService.setHealthRating(); await app.services.projectHealthService.setProjectHealthRating(project.id);
await app.request await app.request
.get(`/api/admin/projects/${project.id}/health-report`) .get(`/api/admin/projects/${project.id}/health-report`)
.expect(200) .expect(200)
@ -177,7 +177,7 @@ test('Health rating endpoint does not include archived toggles when calculating
}) })
.expect(201); .expect(201);
await app.services.projectHealthService.setHealthRating(); await app.services.projectHealthService.setProjectHealthRating(project.id);
await app.request await app.request
.get(`/api/admin/projects/${project.id}/health-report`) .get(`/api/admin/projects/${project.id}/health-report`)
.expect(200) .expect(200)
@ -232,7 +232,7 @@ test('Health rating endpoint correctly handles potentially stale toggles', async
createdAt: new Date(2019, 5, 1), createdAt: new Date(2019, 5, 1),
}) })
.expect(201); .expect(201);
await app.services.projectHealthService.setHealthRating(); await app.services.projectHealthService.setProjectHealthRating(project.id);
await app.request await app.request
.get(`/api/admin/projects/${project.id}/health-report`) .get(`/api/admin/projects/${project.id}/health-report`)
.expect(200) .expect(200)
@ -339,7 +339,7 @@ test('Sorts environments correctly if sort order is equal', async () => {
}); });
test('Update update_at when setHealth runs', async () => { test('Update update_at when setHealth runs', async () => {
await app.services.projectHealthService.setHealthRating(); await app.services.projectHealthService.setProjectHealthRating('default');
await app.request await app.request
.get('/api/admin/projects/default/health-report') .get('/api/admin/projects/default/health-report')
.expect(200) .expect(200)