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:
martmull 2024-08-01 11:38:31 +02:00 committed by GitHub
parent 0f69106558
commit ae423f5e75
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 151 additions and 65 deletions

View File

@ -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 {
CODE = 'CODE',
}
export type WorkflowAction = {
type CommonWorkflowAction = {
name: string;
displayName: string;
type: WorkflowActionType;
valid: boolean;
settings: WorkflowSettingsType;
nextAction?: WorkflowAction;
};
type WorkflowCodeAction = CommonWorkflowAction & {
type: WorkflowActionType.CODE;
settings: WorkflowCodeSettingsType;
};
export type WorkflowAction = WorkflowCodeAction & {
nextAction: WorkflowAction;
};

View File

@ -0,0 +1,10 @@
type WorkflowError = {
errorType: string;
errorMessage: string;
stackTrace: string;
};
export type WorkflowResult = {
data: object | null;
error?: WorkflowError;
};

View File

@ -1,8 +1,4 @@
export type WorkflowCodeSettingsType = {
serverlessFunctionId: string;
};
export type WorkflowSettingsType = {
type WorkflowBaseSettingsType = {
errorHandlingOptions: {
retryOnFailure: {
value: boolean;
@ -11,4 +7,8 @@ export type WorkflowSettingsType = {
value: boolean;
};
};
} & WorkflowCodeSettingsType;
};
export type WorkflowCodeSettingsType = WorkflowBaseSettingsType & {
serverlessFunctionId: string;
};

View File

@ -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}'`,
);
}
}
}

View File

@ -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>;
}

View File

@ -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 {}

View File

@ -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 }) };
}
}

View File

@ -3,10 +3,10 @@ import { Module } from '@nestjs/common';
import { WorkflowRunnerService } from 'src/modules/workflow/workflow-runner/workflow-runner.service';
import { WorkflowRunnerJob } from 'src/modules/workflow/workflow-runner/workflow-runner.job';
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({
imports: [WorkflowCommonModule, ServerlessFunctionModule],
imports: [WorkflowCommonModule, WorkflowActionRunnerModule],
providers: [WorkflowRunnerService, WorkflowRunnerJob],
exports: [WorkflowRunnerService],
})

View File

@ -1,21 +1,14 @@
import { Injectable } from '@nestjs/common';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import {
WorkflowTriggerException,
WorkflowTriggerExceptionCode,
} from 'src/modules/workflow/workflow-trigger/workflow-trigger.exception';
import {
WorkflowAction,
WorkflowActionType,
} from 'src/modules/workflow/common/types/workflow-action.type';
import { WorkflowAction } from 'src/modules/workflow/common/types/workflow-action.type';
import { WorkflowActionRunnerFactory } from 'src/modules/workflow/workflow-action-runner/workflow-action-runner.factory';
const MAX_RETRIES_ON_FAILURE = 3;
@Injectable()
export class WorkflowRunnerService {
constructor(
private readonly serverlessFunctionService: ServerlessFunctionService,
private readonly workflowActionRunnerFactory: WorkflowActionRunnerFactory,
) {}
async run({
@ -33,51 +26,48 @@ export class WorkflowRunnerService {
return payload;
}
let result: object | undefined = undefined;
const workflowActionRunner = this.workflowActionRunnerFactory.get(
action.type,
);
switch (action.type) {
case WorkflowActionType.CODE: {
const executionResult = await this.serverlessFunctionService.executeOne(
action.settings.serverlessFunctionId,
workspaceId,
payload,
);
const result = await workflowActionRunner.execute({
action,
workspaceId,
payload,
});
if (executionResult.data) {
result = executionResult.data;
break;
}
if (!executionResult.error) {
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,
);
if (result.data) {
return await this.run({
action: action.nextAction,
workspaceId,
payload: result.data,
});
}
return await this.run({
action: action.nextAction,
workspaceId,
payload: result,
});
if (!result.error) {
throw new Error('Execution result error, no data or error');
}
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;
}
}