mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
optimize the loading of statistics
This commit is contained in:
parent
f82a8562ba
commit
3312f9d7c2
|
@ -95,7 +95,11 @@ export class WorkflowRepository extends Repository<WorkflowEntity> {
|
||||||
.execute();
|
.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 (sharedWorkflowIds.length === 0) return { workflows: [], count: 0 };
|
||||||
|
|
||||||
if (typeof options?.filter?.projectId === 'string' && options.filter.projectId !== '') {
|
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 (isOwnedByIncluded) relations.push('shared', 'shared.project');
|
||||||
|
|
||||||
|
if (includeExecutionStatistics === true) {
|
||||||
|
relations.push('statistics');
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof where.name === 'string' && where.name !== '') {
|
if (typeof where.name === 'string' && where.name !== '') {
|
||||||
where.name = Like(`%${where.name}%`);
|
where.name = Like(`%${where.name}%`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,14 @@ export namespace ListQuery {
|
||||||
* Slim workflow returned from a list query operation.
|
* Slim workflow returned from a list query operation.
|
||||||
*/
|
*/
|
||||||
export namespace Workflow {
|
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'> &
|
type BaseFields = Pick<WorkflowEntity, 'id'> &
|
||||||
Partial<Pick<WorkflowEntity, OptionalBaseFields>>;
|
Partial<Pick<WorkflowEntity, OptionalBaseFields>>;
|
||||||
|
@ -89,10 +96,12 @@ export namespace ListQuery {
|
||||||
type SharedField = Partial<Pick<WorkflowEntity, 'shared'>>;
|
type SharedField = Partial<Pick<WorkflowEntity, 'shared'>>;
|
||||||
|
|
||||||
type OwnedByField = { ownedBy: SlimUser | null; homeProject: SlimProject | null };
|
type OwnedByField = { ownedBy: SlimUser | null; homeProject: SlimProject | null };
|
||||||
|
type ExecutionStatisticsField = { executionStatistics: { errors: number; successes: number } };
|
||||||
|
|
||||||
export type Plain = BaseFields;
|
export type Plain = BaseFields;
|
||||||
|
|
||||||
export type WithSharing = BaseFields & SharedField;
|
export type WithSharing = BaseFields & SharedField;
|
||||||
|
export type WithExecutionStatistics = BaseFields & ExecutionStatisticsField;
|
||||||
|
|
||||||
export type WithOwnership = BaseFields & OwnedByField;
|
export type WithOwnership = BaseFields & OwnedByField;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { WorkflowStatisticsRepository } from '@/databases/repositories/workflow-
|
||||||
import { EventService } from '@/events/event.service';
|
import { EventService } from '@/events/event.service';
|
||||||
import type { WorkflowStatisticsData } from '@/interfaces';
|
import type { WorkflowStatisticsData } from '@/interfaces';
|
||||||
import { Logger } from '@/logging/logger.service';
|
import { Logger } from '@/logging/logger.service';
|
||||||
|
import type { ListQuery } from '@/requests';
|
||||||
import { UserService } from '@/services/user.service';
|
import { UserService } from '@/services/user.service';
|
||||||
import { TypedEmitter } from '@/typed-emitter';
|
import { TypedEmitter } from '@/typed-emitter';
|
||||||
|
|
||||||
|
@ -169,4 +170,21 @@ export class WorkflowStatisticsService extends TypedEmitter<WorkflowStatisticsEv
|
||||||
|
|
||||||
return data;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,11 @@ export class WorkflowService {
|
||||||
});
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line prefer-const
|
// 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)) {
|
if (hasSharing(workflows)) {
|
||||||
workflows = workflows.map((w) => this.ownershipService.addOwnedByAndSharedWith(w));
|
workflows = workflows.map((w) => this.ownershipService.addOwnedByAndSharedWith(w));
|
||||||
|
@ -82,21 +86,11 @@ export class WorkflowService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeExecutionStatistics) {
|
if (includeExecutionStatistics) {
|
||||||
workflows = await Promise.all(
|
workflows = workflows.map((w) => this.workflowStatisticsService.addExecutionStatistics(w));
|
||||||
workflows.map(async (w) => {
|
|
||||||
const stats = await this.workflowStatisticsService.getData(w.id, 'count', 0);
|
|
||||||
return {
|
|
||||||
...w,
|
|
||||||
executionStatistics: {
|
|
||||||
errors: stats.productionError,
|
|
||||||
successes: stats.productionSuccess,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
workflows.forEach((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`
|
// field as part of `addOwnedByAndSharedWith`. We need this field in `addScopes`
|
||||||
// though. So to avoid leaking the information we just delete it.
|
// though. So to avoid leaking the information we just delete it.
|
||||||
delete w.shared;
|
delete w.shared;
|
||||||
|
|
Loading…
Reference in a new issue