Skip to content

Commit

Permalink
Update workflow version struct (#6716)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
thomtrp authored Aug 22, 2024
1 parent 579c2eb commit 0a77003
Show file tree
Hide file tree
Showing 18 changed files with 131 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ export const WORKFLOW_VERSION_STANDARD_FIELD_IDS = {
workflow: '20202020-afa3-46c3-91b0-0631ca6aa1c8',
trigger: '20202020-4eae-43e7-86e0-212b41a30b48',
runs: '20202020-1d08-46df-901a-85045f18099a',
steps: '20202020-5988-4a64-b94a-1f9b7b989039',
};

export const WORKSPACE_MEMBER_STANDARD_FIELD_IDS = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
import { WorkflowStep } from 'src/modules/workflow/common/types/workflow-step.type';
import { WorkflowTrigger } from 'src/modules/workflow/common/types/workflow-trigger.type';

@WorkspaceEntity({
Expand Down Expand Up @@ -51,11 +52,19 @@ export class WorkflowVersionWorkspaceEntity extends BaseWorkspaceEntity {
type: FieldMetadataType.RAW_JSON,
label: 'Version trigger',
description: 'Json object to provide trigger',
icon: 'IconPlayerPlay',
})
@WorkspaceIsNullable()
trigger: WorkflowTrigger | null;

@WorkspaceField({
standardId: WORKFLOW_VERSION_STANDARD_FIELD_IDS.steps,
type: FieldMetadataType.RAW_JSON,
label: 'Version steps',
description: 'Json object to provide steps',
})
@WorkspaceIsNullable()
steps: WorkflowStep[] | null;

// Relations
@WorkspaceRelation({
standardId: WORKFLOW_VERSION_STANDARD_FIELD_IDS.workflow,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type WorkflowBaseSettingsType = {
type BaseWorkflowSettings = {
errorHandlingOptions: {
retryOnFailure: {
value: boolean;
Expand All @@ -9,6 +9,6 @@ type WorkflowBaseSettingsType = {
};
};

export type WorkflowCodeSettingsType = WorkflowBaseSettingsType & {
export type WorkflowCodeSettings = BaseWorkflowSettings & {
serverlessFunctionId: string;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { WorkflowCodeSettings } from 'src/modules/workflow/common/types/workflow-settings.type';

export enum WorkflowStepType {
CODE_ACTION = 'CODE_ACTION',
}

type BaseWorkflowStep = {
id: string;
name: string;
valid: boolean;
};

export type WorkflowCodeStep = BaseWorkflowStep & {
type: WorkflowStepType.CODE_ACTION;
settings: WorkflowCodeSettings;
};

export type WorkflowStep = WorkflowCodeStep;
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';

export enum WorkflowTriggerType {
DATABASE_EVENT = 'DATABASE_EVENT',
}

type BaseTrigger = {
name: string;
type: WorkflowTriggerType;
input?: object;
nextAction?: WorkflowAction;
};

export type WorkflowDatabaseEventTrigger = BaseTrigger & {
type: WorkflowTriggerType.DATABASE_EVENT;
settings: {
eventName: string;
triggerName: string;
};
};

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

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

import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
import { WorkflowActionExecutorModule } from 'src/modules/workflow/workflow-action-executor/workflow-action-executor.module';
import { WorkflowExecutorWorkspaceService } from 'src/modules/workflow/workflow-executor/workflow-executor.workspace-service';
import { WorkflowStepExecutorModule } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.module';

@Module({
imports: [WorkflowCommonModule, WorkflowActionExecutorModule],
imports: [WorkflowCommonModule, WorkflowStepExecutorModule],
providers: [WorkflowExecutorWorkspaceService],
exports: [WorkflowExecutorWorkspaceService],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Injectable } from '@nestjs/common';

import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
import { WorkflowActionExecutorFactory } from 'src/modules/workflow/workflow-action-executor/workflow-action-executor.factory';
import { WorkflowStep } from 'src/modules/workflow/common/types/workflow-step.type';
import {
WorkflowExecutorException,
WorkflowExecutorExceptionCode,
} from 'src/modules/workflow/workflow-executor/workflow-executor.exception';
import { WorkflowStepExecutorFactory } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.factory';

const MAX_RETRIES_ON_FAILURE = 3;

Expand All @@ -17,36 +17,41 @@ export type WorkflowExecutionOutput = {
@Injectable()
export class WorkflowExecutorWorkspaceService {
constructor(
private readonly workflowActionExecutorFactory: WorkflowActionExecutorFactory,
private readonly workflowStepExecutorFactory: WorkflowStepExecutorFactory,
) {}

async execute({
action,
currentStepIndex,
steps,
payload,
attemptCount = 1,
}: {
action?: WorkflowAction;
currentStepIndex: number;
steps: WorkflowStep[];
payload?: object;
attemptCount?: number;
}): Promise<WorkflowExecutionOutput> {
if (!action) {
if (currentStepIndex >= steps.length) {
return {
data: payload,
};
}

const workflowActionExecutor = this.workflowActionExecutorFactory.get(
action.type,
const step = steps[currentStepIndex];

const workflowStepExecutor = this.workflowStepExecutorFactory.get(
step.type,
);

const result = await workflowActionExecutor.execute({
action,
const result = await workflowStepExecutor.execute({
step,
payload,
});

if (result.data) {
return await this.execute({
action: action.nextAction,
currentStepIndex: currentStepIndex + 1,
steps,
payload: result.data,
});
}
Expand All @@ -58,19 +63,21 @@ export class WorkflowExecutorWorkspaceService {
);
}

if (action.settings.errorHandlingOptions.continueOnFailure.value) {
if (step.settings.errorHandlingOptions.continueOnFailure.value) {
return await this.execute({
action: action.nextAction,
currentStepIndex: currentStepIndex + 1,
steps,
payload,
});
}

if (
action.settings.errorHandlingOptions.retryOnFailure.value &&
step.settings.errorHandlingOptions.retryOnFailure.value &&
attemptCount < MAX_RETRIES_ON_FAILURE
) {
return await this.execute({
action,
currentStepIndex,
steps,
payload,
attemptCount: attemptCount + 1,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export class RunWorkflowJob {

try {
await this.workflowExecutorWorkspaceService.execute({
action: workflowVersion.trigger.nextAction,
currentStepIndex: 0,
steps: workflowVersion.steps || [],
payload,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { CustomException } from 'src/utils/custom-exception';

export class WorkflowStepExecutorException extends CustomException {
code: WorkflowStepExecutorExceptionCode;
constructor(message: string, code: WorkflowStepExecutorExceptionCode) {
super(message, code);
}
}

export enum WorkflowStepExecutorExceptionCode {
SCOPED_WORKSPACE_NOT_FOUND = 'SCOPED_WORKSPACE_NOT_FOUND',
INVALID_STEP_TYPE = 'INVALID_STEP_TYPE',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Injectable } from '@nestjs/common';

import { WorkflowStepType } from 'src/modules/workflow/common/types/workflow-step.type';
import {
WorkflowStepExecutorException,
WorkflowStepExecutorExceptionCode,
} from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.exception';
import { WorkflowStepExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.interface';
import { CodeActionExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executors/code-action-executor';

@Injectable()
export class WorkflowStepExecutorFactory {
constructor(private readonly codeActionExecutor: CodeActionExecutor) {}

get(stepType: WorkflowStepType): WorkflowStepExecutor {
switch (stepType) {
case WorkflowStepType.CODE_ACTION:
return this.codeActionExecutor;
default:
throw new WorkflowStepExecutorException(
`Workflow step executor not found for step type '${stepType}'`,
WorkflowStepExecutorExceptionCode.INVALID_STEP_TYPE,
);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
import { WorkflowResult } from 'src/modules/workflow/common/types/workflow-result.type';
import { WorkflowStep } from 'src/modules/workflow/common/types/workflow-step.type';

export interface WorkflowActionExecutor {
export interface WorkflowStepExecutor {
execute({
action,
step,
payload,
}: {
action: WorkflowAction;
step: WorkflowStep;
payload?: object;
}): Promise<WorkflowResult>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Module } from '@nestjs/common';

import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
import { WorkflowStepExecutorFactory } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.factory';
import { CodeActionExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executors/code-action-executor';

@Module({
imports: [ServerlessFunctionModule],
providers: [
WorkflowStepExecutorFactory,
CodeActionExecutor,
ScopedWorkspaceContextFactory,
],
exports: [WorkflowStepExecutorFactory],
})
export class WorkflowStepExecutorModule {}
Loading

0 comments on commit 0a77003

Please sign in to comment.