Remove serverless functions on soft delete (#9438)

Delete workflow versions serverless functions when soft delete workflow
This commit is contained in:
martmull
2025-01-07 16:51:34 +01:00
committed by GitHub
parent 46f51577a3
commit 0c75b244ba
7 changed files with 81 additions and 31 deletions

View File

@ -122,10 +122,10 @@ export class ServerlessFunctionResolver {
try {
await this.checkFeatureFlag(workspaceId);
return await this.serverlessFunctionService.deleteOneServerlessFunction(
input.id,
return await this.serverlessFunctionService.deleteOneServerlessFunction({
id: input.id,
workspaceId,
);
});
} catch (error) {
serverlessFunctionGraphQLApiExceptionHandler(error);
}

View File

@ -205,7 +205,15 @@ export class ServerlessFunctionService {
});
}
async deleteOneServerlessFunction(id: string, workspaceId: string) {
async deleteOneServerlessFunction({
id,
workspaceId,
isHardDeletion = true,
}: {
id: string;
workspaceId: string;
isHardDeletion?: boolean;
}) {
const existingServerlessFunction =
await this.serverlessFunctionRepository.findOneBy({
id,
@ -219,16 +227,17 @@ export class ServerlessFunctionService {
);
}
await this.serverlessFunctionRepository.delete(id);
if (isHardDeletion) {
await this.serverlessFunctionRepository.delete(id);
await this.fileStorageService.delete({
folderPath: getServerlessFolder({
serverlessFunction: existingServerlessFunction,
}),
});
}
await this.serverlessService.delete(existingServerlessFunction);
await this.fileStorageService.delete({
folderPath: getServerlessFolder({
serverlessFunction: existingServerlessFunction,
}),
});
return existingServerlessFunction;
}

View File

@ -18,12 +18,13 @@ export class WorkflowDeleteManyPostQueryHook
) {}
async execute(
_authContext: AuthContext,
authContext: AuthContext,
_objectName: string,
payload: WorkflowWorkspaceEntity[],
): Promise<void> {
this.workflowCommonWorkspaceService.cleanWorkflowsSubEntities(
payload.map((workflow) => workflow.id),
authContext.workspace.id,
);
}
}

View File

@ -18,12 +18,13 @@ export class WorkflowDeleteOnePostQueryHook
) {}
async execute(
_authContext: AuthContext,
authContext: AuthContext,
_objectName: string,
payload: WorkflowWorkspaceEntity[],
): Promise<void> {
this.workflowCommonWorkspaceService.cleanWorkflowsSubEntities(
payload.map((workflow) => workflow.id),
authContext.workspace.id,
);
}
}

View File

@ -25,10 +25,12 @@ import { WorkflowVersionUpdateManyPreQueryHook } from 'src/modules/workflow/comm
import { WorkflowVersionUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-update-one.pre-query.hook';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
@Module({
imports: [
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
ServerlessFunctionModule,
],
providers: [
WorkflowCreateOnePreQueryHook,

View File

@ -8,10 +8,16 @@ import {
WorkflowTriggerException,
WorkflowTriggerExceptionCode,
} from 'src/modules/workflow/workflow-trigger/exceptions/workflow-trigger.exception';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
@Injectable()
export class WorkflowCommonWorkspaceService {
constructor(private readonly twentyORMManager: TwentyORMManager) {}
constructor(
private readonly twentyORMManager: TwentyORMManager,
private readonly serverlessFunctionService: ServerlessFunctionService,
) {}
async getWorkflowVersionOrFail(
workflowVersionId: string,
@ -58,7 +64,10 @@ export class WorkflowCommonWorkspaceService {
return { ...workflowVersion, trigger: workflowVersion.trigger };
}
async cleanWorkflowsSubEntities(workflowIds: string[]): Promise<void> {
async cleanWorkflowsSubEntities(
workflowIds: string[],
workspaceId: string,
): Promise<void> {
const workflowVersionRepository =
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
'workflowVersion',
@ -74,20 +83,48 @@ export class WorkflowCommonWorkspaceService {
'workflowEventListener',
);
Promise.all(
workflowIds.map((workflowId) => {
workflowEventListenerRepository.softDelete({
workflowId,
});
workflowIds.forEach((workflowId) => {
workflowEventListenerRepository.softDelete({
workflowId,
});
workflowRunRepository.softDelete({
workflowId,
});
workflowRunRepository.softDelete({
workflowId,
});
workflowVersionRepository.softDelete({
workflowId,
});
}),
);
workflowVersionRepository.softDelete({
workflowId,
});
this.deleteServerlessFunctions(
workflowVersionRepository,
workflowId,
workspaceId,
);
});
}
private async deleteServerlessFunctions(
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>,
workflowId: string,
workspaceId: string,
) {
const workflowVersions = await workflowVersionRepository.find({
where: {
workflowId,
},
});
workflowVersions.forEach((workflowVersion) => {
workflowVersion.steps?.forEach(async (step) => {
if (step.type === WorkflowActionType.CODE) {
await this.serverlessFunctionService.deleteOneServerlessFunction({
id: step.settings.input.serverlessFunctionId,
workspaceId,
isHardDeletion: false,
});
}
});
});
}
}

View File

@ -511,10 +511,10 @@ export class WorkflowVersionStepWorkspaceService {
}) {
switch (step.type) {
case WorkflowActionType.CODE: {
await this.serverlessFunctionService.deleteOneServerlessFunction(
step.settings.input.serverlessFunctionId,
await this.serverlessFunctionService.deleteOneServerlessFunction({
id: step.settings.input.serverlessFunctionId,
workspaceId,
);
});
break;
}