optimize the loading of statistics

This commit is contained in:
Ivan Atanasov 2024-10-30 16:40:36 +01:00
parent f82a8562ba
commit 3312f9d7c2
No known key found for this signature in database
4 changed files with 44 additions and 15 deletions

View file

@ -95,7 +95,11 @@ export class WorkflowRepository extends Repository<WorkflowEntity> {
.execute();
}
async getMany(sharedWorkflowIds: string[], options?: ListQuery.Options) {
async getMany(
sharedWorkflowIds: string[],
options?: ListQuery.Options,
includeExecutionStatistics?: boolean,
) {
if (sharedWorkflowIds.length === 0) return { workflows: [], count: 0 };
if (typeof options?.filter?.projectId === 'string' && options.filter.projectId !== '') {
@ -143,6 +147,10 @@ export class WorkflowRepository extends Repository<WorkflowEntity> {
if (isOwnedByIncluded) relations.push('shared', 'shared.project');
if (includeExecutionStatistics === true) {
relations.push('statistics');
}
if (typeof where.name === 'string' && where.name !== '') {
where.name = Like(`%${where.name}%`);
}

View file

@ -81,7 +81,14 @@ export namespace ListQuery {
* Slim workflow returned from a list query operation.
*/
export namespace Workflow {
type OptionalBaseFields = 'name' | 'active' | 'versionId' | 'createdAt' | 'updatedAt' | 'tags';
type OptionalBaseFields =
| 'name'
| 'active'
| 'versionId'
| 'createdAt'
| 'updatedAt'
| 'tags'
| 'statistics';
type BaseFields = Pick<WorkflowEntity, 'id'> &
Partial<Pick<WorkflowEntity, OptionalBaseFields>>;
@ -89,10 +96,12 @@ export namespace ListQuery {
type SharedField = Partial<Pick<WorkflowEntity, 'shared'>>;
type OwnedByField = { ownedBy: SlimUser | null; homeProject: SlimProject | null };
type ExecutionStatisticsField = { executionStatistics: { errors: number; successes: number } };
export type Plain = BaseFields;
export type WithSharing = BaseFields & SharedField;
export type WithExecutionStatistics = BaseFields & ExecutionStatisticsField;
export type WithOwnership = BaseFields & OwnedByField;

View file

@ -7,6 +7,7 @@ import { WorkflowStatisticsRepository } from '@/databases/repositories/workflow-
import { EventService } from '@/events/event.service';
import type { WorkflowStatisticsData } from '@/interfaces';
import { Logger } from '@/logging/logger.service';
import type { ListQuery } from '@/requests';
import { UserService } from '@/services/user.service';
import { TypedEmitter } from '@/typed-emitter';
@ -169,4 +170,21 @@ export class WorkflowStatisticsService extends TypedEmitter<WorkflowStatisticsEv
return data;
}
addExecutionStatistics(
entity: ListQuery.Workflow.Plain,
): ListQuery.Workflow.Plain | ListQuery.Workflow.WithExecutionStatistics {
const workflowStatistics = entity.statistics;
Object.assign(entity, {
executionStatistics: {
errors:
workflowStatistics?.find((s) => s.name === StatisticsNames.productionError)?.count ?? 0,
successes:
workflowStatistics?.find((s) => s.name === StatisticsNames.productionSuccess)?.count ?? 0,
},
});
delete entity.statistics;
return entity;
}
}

View file

@ -70,7 +70,11 @@ export class WorkflowService {
});
// eslint-disable-next-line prefer-const
let { workflows, count } = await this.workflowRepository.getMany(sharedWorkflowIds, options);
let { workflows, count } = await this.workflowRepository.getMany(
sharedWorkflowIds,
options,
includeExecutionStatistics,
);
if (hasSharing(workflows)) {
workflows = workflows.map((w) => this.ownershipService.addOwnedByAndSharedWith(w));
@ -82,21 +86,11 @@ export class WorkflowService {
}
if (includeExecutionStatistics) {
workflows = await Promise.all(
workflows.map(async (w) => {
const stats = await this.workflowStatisticsService.getData(w.id, 'count', 0);
return {
...w,
executionStatistics: {
errors: stats.productionError,
successes: stats.productionSuccess,
},
};
}),
);
workflows = workflows.map((w) => this.workflowStatisticsService.addExecutionStatistics(w));
}
workflows.forEach((w) => {
// @ts-expect-error: This is to emulate the old behaviour of removing the shared
// field as part of `addOwnedByAndSharedWith`. We need this field in `addScopes`
// though. So to avoid leaking the information we just delete it.
delete w.shared;