Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build separated executors #10370

Closed
wants to merge 4 commits into from
Closed

Build separated executors #10370

wants to merge 4 commits into from

Conversation

thomtrp
Copy link
Contributor

@thomtrp thomtrp commented Feb 20, 2025

We now have two executors. WorkflowExecutor is responsible for:

  • find the right executor for that step
  • call that executor
  • save the output
  • handle faillure management
  • call itself on next step if there is one

WorkflowActionExecutor finds the right action to execute.

Both returns a base output so the parent caller can also build its output.
I also duplicated the execution functions so we keep on handling the old step format.

Next steps:

  1. Front should be able to read both V1 and V2 format
  2. New steps should be using V2 format. Updates should depend on step current format
  3. Run a script to migrate V1 to V2
  4. Remove V1 handler

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR introduces a significant architectural change to the workflow execution system by separating concerns into distinct WorkflowExecutor and WorkflowActionExecutor components.

  • Added new WorkflowStep type in /packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-step.type.ts to support V2 workflow system
  • Introduced WorkflowStepResult in /packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-step-result.type.ts replacing WorkflowActionResult for standardized output handling
  • Added type guards isWorkflowStep and isWorkflowAction in /packages/twenty-server/src/modules/workflow/workflow-executor/guards/ for step validation
  • Implemented dual execution paths in workflow-action-executor.workspace-service.ts to maintain backward compatibility while introducing new step format
  • Restructured modules to better separate concerns, moving action-specific logic into WorkflowActionExecutorModule

25 file(s) reviewed, 13 comment(s)
Edit PR Review Bot Settings | Greptile

@thomtrp thomtrp force-pushed the add-new-workflow-executor branch from 9fabd21 to 3b9c156 Compare February 21, 2025 13:59
@thomtrp thomtrp force-pushed the add-new-workflow-executor branch from ed7a80f to 9ee4d49 Compare February 21, 2025 14:19
@Devessier Devessier self-requested a review February 21, 2025 14:22
Copy link
Contributor

@Devessier Devessier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really excited by these changes! I wrote a few comments, let's discuss about that. I'm already approving the PR as there is nothing critical.

Great job on the retrocompatibility! We can still execute workflows properly.

Comment on lines +4 to +8
export const isWorkflowAction = (
step: WorkflowStep | WorkflowAction,
): step is WorkflowAction => {
return 'settings' in step;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love these guards 👌

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can check the value of the type property. It seems to be the most substantial separation between the two types.

Suggested change
export const isWorkflowAction = (
step: WorkflowStep | WorkflowAction,
): step is WorkflowAction => {
return 'settings' in step;
};
export const isWorkflowAction = (
step: WorkflowStep | WorkflowAction,
): step is WorkflowAction => {
return Object.values(WorkflowActionType).includes(
step.type as WorkflowActionType,
);
};

I'm unsure how we usually do that in the back-end codebase.

Comment on lines +4 to +8
export const isWorkflowStep = (
step: WorkflowStep | WorkflowAction,
): step is WorkflowStep => {
return 'stepSettings' in step;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here. I would check the type property as it's the most significant difference between the two types.

Suggested change
export const isWorkflowStep = (
step: WorkflowStep | WorkflowAction,
): step is WorkflowStep => {
return 'stepSettings' in step;
};
export const isWorkflowStep = (
step: WorkflowStep | WorkflowAction,
): step is WorkflowStep => {
return Object.values(WorkflowStepType).includes(
step.type as WorkflowStepType,
);
};

Comment on lines +21 to +23
/**
* To migrate to WorkflowActionStepSettings once the V2 workflow is released.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

const updatedStepsOutput = {
...workflowExecutorState.stepsOutput,
[step.id]: updatedStepOutput,
if (result.result) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤓 nitpick:result.result. Maybe we can rename the result variable to read stepExecution.result

Comment on lines +156 to +162
return this.execute({
workflowRunId,
currentStepIndex: currentStepIndex + 1,
steps,
context,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent 👍


let result: WorkflowActionResult;
const stepExecutor = this.getStepExecutor(step);
let result;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result variable was typed in the previous version. Why did you remove the explicit type?

);
}

let result;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be great to strictly type the result variable.

import { WorkflowExecutorInput } from 'src/modules/workflow/workflow-executor/types/workflow-executor-input';
import { WorkflowStepResult } from 'src/modules/workflow/workflow-executor/types/workflow-step-result.type';

export interface WorkflowExecutor {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this interface 💪

Comment on lines +65 to +73
} else {
return this.executeStep({
currentStepIndex,
steps,
context,
attemptCount,
workflowRunId,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤓 nitpick: I think it would be "safer" to use else if (isWorkflowStep(step)) to not fall in an unwanted case.‏

Comment on lines +21 to +24
settings?: object;

@Field(() => graphqlTypeJson)
stepSettings?: object;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remind me why we split the settings into two properties?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

settings is the previous field that will be copied into actionSettings, subfield of stepSettings

@thomtrp thomtrp closed this Feb 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants