mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-23 14:03:35 +03:00
Improve typing definition (#6481)
- added typing for workflow-runner results - fix workflow typing - add a `workflow-action-runner` submodule that contains factories for action runners - added code-action-runner - simplified code
This commit is contained in:
parent
0f69106558
commit
ae423f5e75
@ -1,14 +1,20 @@
|
|||||||
import { WorkflowSettingsType } from 'src/modules/workflow/common/types/workflow-settings.type';
|
import { WorkflowCodeSettingsType } from 'src/modules/workflow/common/types/workflow-settings.type';
|
||||||
|
|
||||||
export enum WorkflowActionType {
|
export enum WorkflowActionType {
|
||||||
CODE = 'CODE',
|
CODE = 'CODE',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WorkflowAction = {
|
type CommonWorkflowAction = {
|
||||||
name: string;
|
name: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
type: WorkflowActionType;
|
|
||||||
valid: boolean;
|
valid: boolean;
|
||||||
settings: WorkflowSettingsType;
|
};
|
||||||
nextAction?: WorkflowAction;
|
|
||||||
|
type WorkflowCodeAction = CommonWorkflowAction & {
|
||||||
|
type: WorkflowActionType.CODE;
|
||||||
|
settings: WorkflowCodeSettingsType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowAction = WorkflowCodeAction & {
|
||||||
|
nextAction: WorkflowAction;
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
type WorkflowError = {
|
||||||
|
errorType: string;
|
||||||
|
errorMessage: string;
|
||||||
|
stackTrace: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowResult = {
|
||||||
|
data: object | null;
|
||||||
|
error?: WorkflowError;
|
||||||
|
};
|
@ -1,8 +1,4 @@
|
|||||||
export type WorkflowCodeSettingsType = {
|
type WorkflowBaseSettingsType = {
|
||||||
serverlessFunctionId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowSettingsType = {
|
|
||||||
errorHandlingOptions: {
|
errorHandlingOptions: {
|
||||||
retryOnFailure: {
|
retryOnFailure: {
|
||||||
value: boolean;
|
value: boolean;
|
||||||
@ -11,4 +7,8 @@ export type WorkflowSettingsType = {
|
|||||||
value: boolean;
|
value: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} & WorkflowCodeSettingsType;
|
};
|
||||||
|
|
||||||
|
export type WorkflowCodeSettingsType = WorkflowBaseSettingsType & {
|
||||||
|
serverlessFunctionId: string;
|
||||||
|
};
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { CodeWorkflowActionRunner } from 'src/modules/workflow/workflow-action-runner/workflow-action-runners/code-workflow-action-runner';
|
||||||
|
import { WorkflowActionType } from 'src/modules/workflow/common/types/workflow-action.type';
|
||||||
|
import { WorkflowActionRunner } from 'src/modules/workflow/workflow-action-runner/workflow-action-runner.interface';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WorkflowActionRunnerFactory {
|
||||||
|
constructor(
|
||||||
|
private readonly codeWorkflowActionRunner: CodeWorkflowActionRunner,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
get(actionType: WorkflowActionType): WorkflowActionRunner {
|
||||||
|
switch (actionType) {
|
||||||
|
case WorkflowActionType.CODE:
|
||||||
|
return this.codeWorkflowActionRunner;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Workflow action executor not found for action type '${actionType}'`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import { WorkflowResult } from 'src/modules/workflow/common/types/workflow-result.type';
|
||||||
|
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
|
||||||
|
|
||||||
|
export interface WorkflowActionRunner {
|
||||||
|
execute({
|
||||||
|
action,
|
||||||
|
workspaceId,
|
||||||
|
payload,
|
||||||
|
}: {
|
||||||
|
action: WorkflowAction;
|
||||||
|
workspaceId: string;
|
||||||
|
payload?: object;
|
||||||
|
}): Promise<WorkflowResult>;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { WorkflowActionRunnerFactory } from 'src/modules/workflow/workflow-action-runner/workflow-action-runner.factory';
|
||||||
|
import { CodeWorkflowActionRunner } from 'src/modules/workflow/workflow-action-runner/workflow-action-runners/code-workflow-action-runner';
|
||||||
|
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [ServerlessFunctionModule],
|
||||||
|
providers: [WorkflowActionRunnerFactory, CodeWorkflowActionRunner],
|
||||||
|
exports: [WorkflowActionRunnerFactory],
|
||||||
|
})
|
||||||
|
export class WorkflowActionRunnerModule {}
|
@ -0,0 +1,31 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { WorkflowActionRunner } from 'src/modules/workflow/workflow-action-runner/workflow-action-runner.interface';
|
||||||
|
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
|
||||||
|
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
||||||
|
import { WorkflowResult } from 'src/modules/workflow/common/types/workflow-result.type';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CodeWorkflowActionRunner implements WorkflowActionRunner {
|
||||||
|
constructor(
|
||||||
|
private readonly serverlessFunctionService: ServerlessFunctionService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute({
|
||||||
|
action,
|
||||||
|
workspaceId,
|
||||||
|
payload,
|
||||||
|
}: {
|
||||||
|
action: WorkflowAction;
|
||||||
|
workspaceId: string;
|
||||||
|
payload?: object;
|
||||||
|
}): Promise<WorkflowResult> {
|
||||||
|
const result = await this.serverlessFunctionService.executeOne(
|
||||||
|
action.settings.serverlessFunctionId,
|
||||||
|
workspaceId,
|
||||||
|
payload,
|
||||||
|
);
|
||||||
|
|
||||||
|
return { data: result.data, ...(result.error && { error: result.error }) };
|
||||||
|
}
|
||||||
|
}
|
@ -3,10 +3,10 @@ import { Module } from '@nestjs/common';
|
|||||||
import { WorkflowRunnerService } from 'src/modules/workflow/workflow-runner/workflow-runner.service';
|
import { WorkflowRunnerService } from 'src/modules/workflow/workflow-runner/workflow-runner.service';
|
||||||
import { WorkflowRunnerJob } from 'src/modules/workflow/workflow-runner/workflow-runner.job';
|
import { WorkflowRunnerJob } from 'src/modules/workflow/workflow-runner/workflow-runner.job';
|
||||||
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
||||||
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
|
import { WorkflowActionRunnerModule } from 'src/modules/workflow/workflow-action-runner/workflow-action-runner.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [WorkflowCommonModule, ServerlessFunctionModule],
|
imports: [WorkflowCommonModule, WorkflowActionRunnerModule],
|
||||||
providers: [WorkflowRunnerService, WorkflowRunnerJob],
|
providers: [WorkflowRunnerService, WorkflowRunnerJob],
|
||||||
exports: [WorkflowRunnerService],
|
exports: [WorkflowRunnerService],
|
||||||
})
|
})
|
||||||
|
@ -1,21 +1,14 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
|
||||||
import {
|
import { WorkflowActionRunnerFactory } from 'src/modules/workflow/workflow-action-runner/workflow-action-runner.factory';
|
||||||
WorkflowTriggerException,
|
|
||||||
WorkflowTriggerExceptionCode,
|
|
||||||
} from 'src/modules/workflow/workflow-trigger/workflow-trigger.exception';
|
|
||||||
import {
|
|
||||||
WorkflowAction,
|
|
||||||
WorkflowActionType,
|
|
||||||
} from 'src/modules/workflow/common/types/workflow-action.type';
|
|
||||||
|
|
||||||
const MAX_RETRIES_ON_FAILURE = 3;
|
const MAX_RETRIES_ON_FAILURE = 3;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkflowRunnerService {
|
export class WorkflowRunnerService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly serverlessFunctionService: ServerlessFunctionService,
|
private readonly workflowActionRunnerFactory: WorkflowActionRunnerFactory,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async run({
|
async run({
|
||||||
@ -33,51 +26,48 @@ export class WorkflowRunnerService {
|
|||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
let result: object | undefined = undefined;
|
const workflowActionRunner = this.workflowActionRunnerFactory.get(
|
||||||
|
action.type,
|
||||||
|
);
|
||||||
|
|
||||||
switch (action.type) {
|
const result = await workflowActionRunner.execute({
|
||||||
case WorkflowActionType.CODE: {
|
action,
|
||||||
const executionResult = await this.serverlessFunctionService.executeOne(
|
workspaceId,
|
||||||
action.settings.serverlessFunctionId,
|
payload,
|
||||||
workspaceId,
|
});
|
||||||
payload,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (executionResult.data) {
|
if (result.data) {
|
||||||
result = executionResult.data;
|
return await this.run({
|
||||||
break;
|
action: action.nextAction,
|
||||||
}
|
workspaceId,
|
||||||
if (!executionResult.error) {
|
payload: result.data,
|
||||||
throw new Error('Execution result error, no data or error');
|
});
|
||||||
}
|
|
||||||
if (action.settings.errorHandlingOptions.continueOnFailure.value) {
|
|
||||||
result = payload;
|
|
||||||
break;
|
|
||||||
} else if (
|
|
||||||
action.settings.errorHandlingOptions.retryOnFailure.value &&
|
|
||||||
attemptCount < MAX_RETRIES_ON_FAILURE
|
|
||||||
) {
|
|
||||||
return await this.run({
|
|
||||||
action,
|
|
||||||
workspaceId,
|
|
||||||
payload,
|
|
||||||
attemptCount: attemptCount + 1,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return executionResult.error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new WorkflowTriggerException(
|
|
||||||
`Unknown action type '${action.type}'`,
|
|
||||||
WorkflowTriggerExceptionCode.INVALID_ACTION_TYPE,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.run({
|
if (!result.error) {
|
||||||
action: action.nextAction,
|
throw new Error('Execution result error, no data or error');
|
||||||
workspaceId,
|
}
|
||||||
payload: result,
|
|
||||||
});
|
if (action.settings.errorHandlingOptions.continueOnFailure.value) {
|
||||||
|
return await this.run({
|
||||||
|
action: action.nextAction,
|
||||||
|
workspaceId,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
action.settings.errorHandlingOptions.retryOnFailure.value &&
|
||||||
|
attemptCount < MAX_RETRIES_ON_FAILURE
|
||||||
|
) {
|
||||||
|
return await this.run({
|
||||||
|
action,
|
||||||
|
workspaceId,
|
||||||
|
payload,
|
||||||
|
attemptCount: attemptCount + 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user