fix(core): Remove circular dependency in WorkflowService and ActiveWorkflowRunner (#8128)
## Summary A circular dependency between `WorkflowService` and `ActiveWorkflowRunner` is sometimes causing `this.activeWorkflowRunner` to be `undefined` in `WorkflowService`. Breaking this circular dependency should hopefully fix this issue. ## Related tickets and issues #8122 ## Review / Merge checklist - [x] PR title and summary are descriptive - [ ] Tests included
This commit is contained in:
committed by
GitHub
parent
e9c7fd7397
commit
21788d9153
@@ -18,6 +18,7 @@ import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
|
||||
@Service()
|
||||
export class EnterpriseWorkflowService {
|
||||
@@ -26,6 +27,7 @@ export class EnterpriseWorkflowService {
|
||||
private readonly userService: UserService,
|
||||
private readonly roleService: RoleService,
|
||||
private readonly sharedWorkflowRepository: SharedWorkflowRepository,
|
||||
private readonly workflowRepository: WorkflowRepository,
|
||||
) {}
|
||||
|
||||
async isOwned(
|
||||
@@ -182,7 +184,7 @@ export class EnterpriseWorkflowService {
|
||||
}
|
||||
|
||||
async preventTampering(workflow: WorkflowEntity, workflowId: string, user: User) {
|
||||
const previousVersion = await this.workflowService.get({ id: workflowId });
|
||||
const previousVersion = await this.workflowRepository.get({ id: workflowId });
|
||||
|
||||
if (!previousVersion) {
|
||||
throw new NotFoundError('Workflow not found');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Container, { Service } from 'typedi';
|
||||
import type { IDataObject, INode, IPinData } from 'n8n-workflow';
|
||||
import { NodeApiError, ErrorReporterProxy as ErrorReporter, Workflow } from 'n8n-workflow';
|
||||
import type { FindManyOptions, FindOptionsSelect, FindOptionsWhere, UpdateResult } from 'typeorm';
|
||||
import type { INode, IPinData } from 'n8n-workflow';
|
||||
import { NodeApiError, Workflow } from 'n8n-workflow';
|
||||
import type { FindManyOptions, FindOptionsSelect, FindOptionsWhere } from 'typeorm';
|
||||
import { In, Like } from 'typeorm';
|
||||
import pick from 'lodash/pick';
|
||||
import omit from 'lodash/omit';
|
||||
@@ -25,7 +25,7 @@ import { whereClause } from '@/UserManagement/UserManagementHelper';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { isStringArray, isWorkflowIdValid } from '@/utils';
|
||||
import { isStringArray } from '@/utils';
|
||||
import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee';
|
||||
import { BinaryDataService } from 'n8n-core';
|
||||
import type { Scope } from '@n8n/permissions';
|
||||
@@ -120,13 +120,6 @@ export class WorkflowService {
|
||||
return pinnedTriggers.find((pt) => pt.name === checkNodeName) ?? null; // partial execution
|
||||
}
|
||||
|
||||
async get(workflow: FindOptionsWhere<WorkflowEntity>, options?: { relations: string[] }) {
|
||||
return this.workflowRepository.findOne({
|
||||
where: workflow,
|
||||
relations: options?.relations,
|
||||
});
|
||||
}
|
||||
|
||||
async getMany(sharedWorkflowIds: string[], options?: ListQuery.Options) {
|
||||
if (sharedWorkflowIds.length === 0) return { workflows: [], count: 0 };
|
||||
|
||||
@@ -512,56 +505,4 @@ export class WorkflowService {
|
||||
|
||||
return sharedWorkflow.workflow;
|
||||
}
|
||||
|
||||
async updateWorkflowTriggerCount(id: string, triggerCount: number): Promise<UpdateResult> {
|
||||
const qb = this.workflowRepository.createQueryBuilder('workflow');
|
||||
return qb
|
||||
.update()
|
||||
.set({
|
||||
triggerCount,
|
||||
updatedAt: () => {
|
||||
if (['mysqldb', 'mariadb'].includes(config.getEnv('database.type'))) {
|
||||
return 'updatedAt';
|
||||
}
|
||||
return '"updatedAt"';
|
||||
},
|
||||
})
|
||||
.where('id = :id', { id })
|
||||
.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the static data if it changed
|
||||
*/
|
||||
async saveStaticData(workflow: Workflow): Promise<void> {
|
||||
if (workflow.staticData.__dataChanged === true) {
|
||||
// Static data of workflow changed and so has to be saved
|
||||
if (isWorkflowIdValid(workflow.id)) {
|
||||
// Workflow is saved so update in database
|
||||
try {
|
||||
await this.saveStaticDataById(workflow.id, workflow.staticData);
|
||||
workflow.staticData.__dataChanged = false;
|
||||
} catch (error) {
|
||||
ErrorReporter.error(error);
|
||||
this.logger.error(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
`There was a problem saving the workflow with id "${workflow.id}" to save changed Data: "${error.message}"`,
|
||||
{ workflowId: workflow.id },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given static data on workflow
|
||||
*
|
||||
* @param {(string)} workflowId The id of the workflow to save data on
|
||||
* @param {IDataObject} newStaticData The static data to save
|
||||
*/
|
||||
async saveStaticDataById(workflowId: string, newStaticData: IDataObject): Promise<void> {
|
||||
await this.workflowRepository.update(workflowId, {
|
||||
staticData: newStaticData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
41
packages/cli/src/workflows/workflowStaticData.service.ts
Normal file
41
packages/cli/src/workflows/workflowStaticData.service.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Service } from 'typedi';
|
||||
import { type IDataObject, type Workflow, ErrorReporterProxy as ErrorReporter } from 'n8n-workflow';
|
||||
import { Logger } from '@/Logger';
|
||||
import { WorkflowRepository } from '@db/repositories/workflow.repository';
|
||||
import { isWorkflowIdValid } from '@/utils';
|
||||
|
||||
@Service()
|
||||
export class WorkflowStaticDataService {
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly workflowRepository: WorkflowRepository,
|
||||
) {}
|
||||
|
||||
/** Saves the static data if it changed */
|
||||
async saveStaticData(workflow: Workflow): Promise<void> {
|
||||
if (workflow.staticData.__dataChanged === true) {
|
||||
// Static data of workflow changed and so has to be saved
|
||||
if (isWorkflowIdValid(workflow.id)) {
|
||||
// Workflow is saved so update in database
|
||||
try {
|
||||
await this.saveStaticDataById(workflow.id, workflow.staticData);
|
||||
workflow.staticData.__dataChanged = false;
|
||||
} catch (error) {
|
||||
ErrorReporter.error(error);
|
||||
this.logger.error(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
`There was a problem saving the workflow with id "${workflow.id}" to save changed Data: "${error.message}"`,
|
||||
{ workflowId: workflow.id },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Saves the given static data on workflow */
|
||||
async saveStaticDataById(workflowId: string, newStaticData: IDataObject): Promise<void> {
|
||||
await this.workflowRepository.update(workflowId, {
|
||||
staticData: newStaticData,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { InternalServerError } from '@/errors/response-errors/internal-server.error';
|
||||
import { WorkflowService } from './workflow.service';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
|
||||
export const EEWorkflowController = express.Router();
|
||||
|
||||
@@ -129,7 +130,7 @@ EEWorkflowController.get(
|
||||
relations.push('tags');
|
||||
}
|
||||
|
||||
const workflow = await Container.get(WorkflowService).get({ id: workflowId }, { relations });
|
||||
const workflow = await Container.get(WorkflowRepository).get({ id: workflowId }, { relations });
|
||||
|
||||
if (!workflow) {
|
||||
throw new NotFoundError(`Workflow with ID "${workflowId}" does not exist`);
|
||||
|
||||
Reference in New Issue
Block a user