Add workflow runner (#6458)
- add workflow runner module
- add an endpoint to trigger a workflow via api
- improve error handling for serverless functions
## Testing
- create 2 serverless functions
- create a workflow
- create this workflow Version
```
{
"type": "MANUAL",
"input": {"b": "bb"},
"nextAction": {
"name": "step_1",
"displayName": "Code",
"type": "CODE",
"valid": true,
"settings": {
"serverlessFunctionId": "Serverless function 1 Id",
"errorHandlingOptions": {
"retryOnFailure": {
"value": false
},
"continueOnFailure": {
"value": false
}
}
},
"nextAction": {
"name": "step_1",
"displayName": "Code",
"type": "CODE",
"valid": true,
"settings": {
"serverlessFunctionId": "Serverless function 1 Id",
"errorHandlingOptions": {
"retryOnFailure": {
"value": false
},
"continueOnFailure": {
"value": false
}
}
},
"nextAction": {
"name": "step_1",
"displayName": "Code",
"type": "CODE",
"valid": true,
"settings": {
"serverlessFunctionId": "Serverless function 2 Id",
"errorHandlingOptions": {
"retryOnFailure": {
"value": false
},
"continueOnFailure": {
"value": false
}
}
}
}
}
}
}
`
``
- call
```
mutation Trigger {
triggerWorkflow(workflowVersionId: "WORKFLOW_VERSION_ID") {
result
}
}
```
- try when errors are injected in serverless function
This commit is contained in:
@ -1,13 +1,44 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
|
||||
|
||||
import { IsObject } from 'class-validator';
|
||||
import { IsObject, IsOptional } from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
|
||||
export enum ServerlessFunctionExecutionStatus {
|
||||
SUCCESS = 'SUCCESS',
|
||||
ERROR = 'ERROR',
|
||||
}
|
||||
|
||||
registerEnumType(ServerlessFunctionExecutionStatus, {
|
||||
name: 'ServerlessFunctionExecutionStatus',
|
||||
description: 'Status of the serverless function execution',
|
||||
});
|
||||
|
||||
@ObjectType('ServerlessFunctionExecutionResult')
|
||||
export class ServerlessFunctionExecutionResultDto {
|
||||
export class ServerlessFunctionExecutionResultDTO {
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, {
|
||||
description: 'Execution result in JSON format',
|
||||
nullable: true,
|
||||
})
|
||||
result: JSON;
|
||||
data?: JSON;
|
||||
|
||||
@Field({ description: 'Execution duration in milliseconds' })
|
||||
duration: number;
|
||||
|
||||
@Field(() => ServerlessFunctionExecutionStatus, {
|
||||
description: 'Execution status',
|
||||
})
|
||||
status: ServerlessFunctionExecutionStatus;
|
||||
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
@Field(() => graphqlTypeJson, {
|
||||
description: 'Execution error in JSON format',
|
||||
nullable: true,
|
||||
})
|
||||
error?: {
|
||||
errorType: string;
|
||||
errorMessage: string;
|
||||
stackTrace: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ registerEnumType(ServerlessFunctionSyncStatus, {
|
||||
defaultResultSize: 10,
|
||||
maxResultsSize: 1000,
|
||||
})
|
||||
export class ServerlessFunctionDto {
|
||||
export class ServerlessFunctionDTO {
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
@IDField(() => UUIDScalarType)
|
||||
|
||||
@ -13,7 +13,7 @@ import { ServerlessModule } from 'src/engine/integrations/serverless/serverless.
|
||||
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
||||
import { ServerlessFunctionResolver } from 'src/engine/metadata-modules/serverless-function/serverless-function.resolver';
|
||||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
||||
import { ServerlessFunctionDto } from 'src/engine/metadata-modules/serverless-function/dtos/serverless-function.dto';
|
||||
import { ServerlessFunctionDTO } from 'src/engine/metadata-modules/serverless-function/dtos/serverless-function.dto';
|
||||
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
|
||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
|
||||
@ -32,7 +32,7 @@ import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-
|
||||
resolvers: [
|
||||
{
|
||||
EntityClass: ServerlessFunctionEntity,
|
||||
DTOClass: ServerlessFunctionDto,
|
||||
DTOClass: ServerlessFunctionDTO,
|
||||
ServiceClass: ServerlessFunctionService,
|
||||
pagingStrategy: PagingStrategies.CURSOR,
|
||||
read: {
|
||||
|
||||
@ -14,8 +14,8 @@ import { CreateServerlessFunctionFromFileInput } from 'src/engine/metadata-modul
|
||||
import { CreateServerlessFunctionInput } from 'src/engine/metadata-modules/serverless-function/dtos/create-serverless-function.input';
|
||||
import { DeleteServerlessFunctionInput } from 'src/engine/metadata-modules/serverless-function/dtos/delete-serverless-function.input';
|
||||
import { ExecuteServerlessFunctionInput } from 'src/engine/metadata-modules/serverless-function/dtos/execute-serverless-function.input';
|
||||
import { ServerlessFunctionExecutionResultDto } from 'src/engine/metadata-modules/serverless-function/dtos/serverless-function-execution-result.dto';
|
||||
import { ServerlessFunctionDto } from 'src/engine/metadata-modules/serverless-function/dtos/serverless-function.dto';
|
||||
import { ServerlessFunctionExecutionResultDTO } from 'src/engine/metadata-modules/serverless-function/dtos/serverless-function-execution-result.dto';
|
||||
import { ServerlessFunctionDTO } from 'src/engine/metadata-modules/serverless-function/dtos/serverless-function.dto';
|
||||
import { UpdateServerlessFunctionInput } from 'src/engine/metadata-modules/serverless-function/dtos/update-serverless-function.input';
|
||||
import {
|
||||
ServerlessFunctionException,
|
||||
@ -49,7 +49,7 @@ export class ServerlessFunctionResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Mutation(() => ServerlessFunctionDto)
|
||||
@Mutation(() => ServerlessFunctionDTO)
|
||||
async deleteOneServerlessFunction(
|
||||
@Args('input') input: DeleteServerlessFunctionInput,
|
||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||
@ -66,7 +66,7 @@ export class ServerlessFunctionResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Mutation(() => ServerlessFunctionDto)
|
||||
@Mutation(() => ServerlessFunctionDTO)
|
||||
async updateOneServerlessFunction(
|
||||
@Args('input')
|
||||
input: UpdateServerlessFunctionInput,
|
||||
@ -84,7 +84,7 @@ export class ServerlessFunctionResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Mutation(() => ServerlessFunctionDto)
|
||||
@Mutation(() => ServerlessFunctionDTO)
|
||||
async createOneServerlessFunction(
|
||||
@Args('input')
|
||||
input: CreateServerlessFunctionInput,
|
||||
@ -106,7 +106,7 @@ export class ServerlessFunctionResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Mutation(() => ServerlessFunctionDto)
|
||||
@Mutation(() => ServerlessFunctionDTO)
|
||||
async createOneServerlessFunctionFromFile(
|
||||
@Args({ name: 'file', type: () => GraphQLUpload })
|
||||
file: FileUpload,
|
||||
@ -127,7 +127,7 @@ export class ServerlessFunctionResolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Mutation(() => ServerlessFunctionExecutionResultDto)
|
||||
@Mutation(() => ServerlessFunctionExecutionResultDTO)
|
||||
async executeOneServerlessFunction(
|
||||
@Args() executeServerlessFunctionInput: ExecuteServerlessFunctionInput,
|
||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||
@ -136,13 +136,11 @@ export class ServerlessFunctionResolver {
|
||||
await this.checkFeatureFlag(workspaceId);
|
||||
const { id, payload } = executeServerlessFunctionInput;
|
||||
|
||||
return {
|
||||
result: await this.serverlessFunctionService.executeOne(
|
||||
id,
|
||||
workspaceId,
|
||||
payload,
|
||||
),
|
||||
};
|
||||
return await this.serverlessFunctionService.executeOne(
|
||||
id,
|
||||
workspaceId,
|
||||
payload,
|
||||
);
|
||||
} catch (error) {
|
||||
serverlessFunctionGraphQLApiExceptionHandler(error);
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
import { ServerlessExecuteResult } from 'src/engine/integrations/serverless/drivers/interfaces/serverless-driver.interface';
|
||||
|
||||
import { ServerlessService } from 'src/engine/integrations/serverless/serverless.service';
|
||||
import {
|
||||
@ -41,7 +42,7 @@ export class ServerlessFunctionService extends TypeOrmQueryService<ServerlessFun
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
payload: object | undefined = undefined,
|
||||
) {
|
||||
): Promise<ServerlessExecuteResult> {
|
||||
const functionToExecute = await this.serverlessFunctionRepository.findOne({
|
||||
where: {
|
||||
id,
|
||||
|
||||
Reference in New Issue
Block a user