Skip to content

Commit 0a77003

Browse files
authored
Update workflow version struct (#6716)
We want to avoid the nested structure of active pieces. Steps to execute will now be separated from the trigger. It will be an array executed sequentially. For now a step can only be an action. But at some point it will also be a branch or a loop
1 parent 579c2eb commit 0a77003

18 files changed

+131
-114
lines changed

packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts

+1
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ export const WORKFLOW_VERSION_STANDARD_FIELD_IDS = {
425425
workflow: '20202020-afa3-46c3-91b0-0631ca6aa1c8',
426426
trigger: '20202020-4eae-43e7-86e0-212b41a30b48',
427427
runs: '20202020-1d08-46df-901a-85045f18099a',
428+
steps: '20202020-5988-4a64-b94a-1f9b7b989039',
428429
};
429430

430431
export const WORKSPACE_MEMBER_STANDARD_FIELD_IDS = {

packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
2222
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
2323
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
24+
import { WorkflowStep } from 'src/modules/workflow/common/types/workflow-step.type';
2425
import { WorkflowTrigger } from 'src/modules/workflow/common/types/workflow-trigger.type';
2526

2627
@WorkspaceEntity({
@@ -51,11 +52,19 @@ export class WorkflowVersionWorkspaceEntity extends BaseWorkspaceEntity {
5152
type: FieldMetadataType.RAW_JSON,
5253
label: 'Version trigger',
5354
description: 'Json object to provide trigger',
54-
icon: 'IconPlayerPlay',
5555
})
5656
@WorkspaceIsNullable()
5757
trigger: WorkflowTrigger | null;
5858

59+
@WorkspaceField({
60+
standardId: WORKFLOW_VERSION_STANDARD_FIELD_IDS.steps,
61+
type: FieldMetadataType.RAW_JSON,
62+
label: 'Version steps',
63+
description: 'Json object to provide steps',
64+
})
65+
@WorkspaceIsNullable()
66+
steps: WorkflowStep[] | null;
67+
5968
// Relations
6069
@WorkspaceRelation({
6170
standardId: WORKFLOW_VERSION_STANDARD_FIELD_IDS.workflow,

packages/twenty-server/src/modules/workflow/common/types/workflow-action.type.ts

-20
This file was deleted.

packages/twenty-server/src/modules/workflow/common/types/workflow-settings.type.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
type WorkflowBaseSettingsType = {
1+
type BaseWorkflowSettings = {
22
errorHandlingOptions: {
33
retryOnFailure: {
44
value: boolean;
@@ -9,6 +9,6 @@ type WorkflowBaseSettingsType = {
99
};
1010
};
1111

12-
export type WorkflowCodeSettingsType = WorkflowBaseSettingsType & {
12+
export type WorkflowCodeSettings = BaseWorkflowSettings & {
1313
serverlessFunctionId: string;
1414
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { WorkflowCodeSettings } from 'src/modules/workflow/common/types/workflow-settings.type';
2+
3+
export enum WorkflowStepType {
4+
CODE_ACTION = 'CODE_ACTION',
5+
}
6+
7+
type BaseWorkflowStep = {
8+
id: string;
9+
name: string;
10+
valid: boolean;
11+
};
12+
13+
export type WorkflowCodeStep = BaseWorkflowStep & {
14+
type: WorkflowStepType.CODE_ACTION;
15+
settings: WorkflowCodeSettings;
16+
};
17+
18+
export type WorkflowStep = WorkflowCodeStep;

packages/twenty-server/src/modules/workflow/common/types/workflow-trigger.type.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
2-
31
export enum WorkflowTriggerType {
42
DATABASE_EVENT = 'DATABASE_EVENT',
53
}
64

75
type BaseTrigger = {
6+
name: string;
87
type: WorkflowTriggerType;
98
input?: object;
10-
nextAction?: WorkflowAction;
119
};
1210

1311
export type WorkflowDatabaseEventTrigger = BaseTrigger & {
1412
type: WorkflowTriggerType.DATABASE_EVENT;
1513
settings: {
1614
eventName: string;
17-
triggerName: string;
1815
};
1916
};
2017

packages/twenty-server/src/modules/workflow/workflow-action-executor/workflow-action-executor.exception.ts

-12
This file was deleted.

packages/twenty-server/src/modules/workflow/workflow-action-executor/workflow-action-executor.factory.ts

-23
This file was deleted.

packages/twenty-server/src/modules/workflow/workflow-action-executor/workflow-action-executor.module.ts

-17
This file was deleted.

packages/twenty-server/src/modules/workflow/workflow-executor/workflow-executor.module.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { Module } from '@nestjs/common';
22

33
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
4-
import { WorkflowActionExecutorModule } from 'src/modules/workflow/workflow-action-executor/workflow-action-executor.module';
54
import { WorkflowExecutorWorkspaceService } from 'src/modules/workflow/workflow-executor/workflow-executor.workspace-service';
5+
import { WorkflowStepExecutorModule } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.module';
66

77
@Module({
8-
imports: [WorkflowCommonModule, WorkflowActionExecutorModule],
8+
imports: [WorkflowCommonModule, WorkflowStepExecutorModule],
99
providers: [WorkflowExecutorWorkspaceService],
1010
exports: [WorkflowExecutorWorkspaceService],
1111
})

packages/twenty-server/src/modules/workflow/workflow-executor/workflow-executor.workspace-service.ts

+22-15
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { Injectable } from '@nestjs/common';
22

3-
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
4-
import { WorkflowActionExecutorFactory } from 'src/modules/workflow/workflow-action-executor/workflow-action-executor.factory';
3+
import { WorkflowStep } from 'src/modules/workflow/common/types/workflow-step.type';
54
import {
65
WorkflowExecutorException,
76
WorkflowExecutorExceptionCode,
87
} from 'src/modules/workflow/workflow-executor/workflow-executor.exception';
8+
import { WorkflowStepExecutorFactory } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.factory';
99

1010
const MAX_RETRIES_ON_FAILURE = 3;
1111

@@ -17,36 +17,41 @@ export type WorkflowExecutionOutput = {
1717
@Injectable()
1818
export class WorkflowExecutorWorkspaceService {
1919
constructor(
20-
private readonly workflowActionExecutorFactory: WorkflowActionExecutorFactory,
20+
private readonly workflowStepExecutorFactory: WorkflowStepExecutorFactory,
2121
) {}
2222

2323
async execute({
24-
action,
24+
currentStepIndex,
25+
steps,
2526
payload,
2627
attemptCount = 1,
2728
}: {
28-
action?: WorkflowAction;
29+
currentStepIndex: number;
30+
steps: WorkflowStep[];
2931
payload?: object;
3032
attemptCount?: number;
3133
}): Promise<WorkflowExecutionOutput> {
32-
if (!action) {
34+
if (currentStepIndex >= steps.length) {
3335
return {
3436
data: payload,
3537
};
3638
}
3739

38-
const workflowActionExecutor = this.workflowActionExecutorFactory.get(
39-
action.type,
40+
const step = steps[currentStepIndex];
41+
42+
const workflowStepExecutor = this.workflowStepExecutorFactory.get(
43+
step.type,
4044
);
4145

42-
const result = await workflowActionExecutor.execute({
43-
action,
46+
const result = await workflowStepExecutor.execute({
47+
step,
4448
payload,
4549
});
4650

4751
if (result.data) {
4852
return await this.execute({
49-
action: action.nextAction,
53+
currentStepIndex: currentStepIndex + 1,
54+
steps,
5055
payload: result.data,
5156
});
5257
}
@@ -58,19 +63,21 @@ export class WorkflowExecutorWorkspaceService {
5863
);
5964
}
6065

61-
if (action.settings.errorHandlingOptions.continueOnFailure.value) {
66+
if (step.settings.errorHandlingOptions.continueOnFailure.value) {
6267
return await this.execute({
63-
action: action.nextAction,
68+
currentStepIndex: currentStepIndex + 1,
69+
steps,
6470
payload,
6571
});
6672
}
6773

6874
if (
69-
action.settings.errorHandlingOptions.retryOnFailure.value &&
75+
step.settings.errorHandlingOptions.retryOnFailure.value &&
7076
attemptCount < MAX_RETRIES_ON_FAILURE
7177
) {
7278
return await this.execute({
73-
action,
79+
currentStepIndex,
80+
steps,
7481
payload,
7582
attemptCount: attemptCount + 1,
7683
});

packages/twenty-server/src/modules/workflow/workflow-runner/jobs/run-workflow.job.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ export class RunWorkflowJob {
3838

3939
try {
4040
await this.workflowExecutorWorkspaceService.execute({
41-
action: workflowVersion.trigger.nextAction,
41+
currentStepIndex: 0,
42+
steps: workflowVersion.steps || [],
4243
payload,
4344
});
4445

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { CustomException } from 'src/utils/custom-exception';
2+
3+
export class WorkflowStepExecutorException extends CustomException {
4+
code: WorkflowStepExecutorExceptionCode;
5+
constructor(message: string, code: WorkflowStepExecutorExceptionCode) {
6+
super(message, code);
7+
}
8+
}
9+
10+
export enum WorkflowStepExecutorExceptionCode {
11+
SCOPED_WORKSPACE_NOT_FOUND = 'SCOPED_WORKSPACE_NOT_FOUND',
12+
INVALID_STEP_TYPE = 'INVALID_STEP_TYPE',
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Injectable } from '@nestjs/common';
2+
3+
import { WorkflowStepType } from 'src/modules/workflow/common/types/workflow-step.type';
4+
import {
5+
WorkflowStepExecutorException,
6+
WorkflowStepExecutorExceptionCode,
7+
} from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.exception';
8+
import { WorkflowStepExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.interface';
9+
import { CodeActionExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executors/code-action-executor';
10+
11+
@Injectable()
12+
export class WorkflowStepExecutorFactory {
13+
constructor(private readonly codeActionExecutor: CodeActionExecutor) {}
14+
15+
get(stepType: WorkflowStepType): WorkflowStepExecutor {
16+
switch (stepType) {
17+
case WorkflowStepType.CODE_ACTION:
18+
return this.codeActionExecutor;
19+
default:
20+
throw new WorkflowStepExecutorException(
21+
`Workflow step executor not found for step type '${stepType}'`,
22+
WorkflowStepExecutorExceptionCode.INVALID_STEP_TYPE,
23+
);
24+
}
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
21
import { WorkflowResult } from 'src/modules/workflow/common/types/workflow-result.type';
2+
import { WorkflowStep } from 'src/modules/workflow/common/types/workflow-step.type';
33

4-
export interface WorkflowActionExecutor {
4+
export interface WorkflowStepExecutor {
55
execute({
6-
action,
6+
step,
77
payload,
88
}: {
9-
action: WorkflowAction;
9+
step: WorkflowStep;
1010
payload?: object;
1111
}): Promise<WorkflowResult>;
1212
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Module } from '@nestjs/common';
2+
3+
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
4+
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
5+
import { WorkflowStepExecutorFactory } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.factory';
6+
import { CodeActionExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executors/code-action-executor';
7+
8+
@Module({
9+
imports: [ServerlessFunctionModule],
10+
providers: [
11+
WorkflowStepExecutorFactory,
12+
CodeActionExecutor,
13+
ScopedWorkspaceContextFactory,
14+
],
15+
exports: [WorkflowStepExecutorFactory],
16+
})
17+
export class WorkflowStepExecutorModule {}

0 commit comments

Comments
 (0)