Poc lambda deployment duration (#10340)

closes https://github.com/twentyhq/core-team-issues/issues/436

## Acheivements
Improve aws lambda deployment time from ~10/15 secs to less that 1 sec

## Done
- migrate with the new code executor architecture for local and lambda
drivers
- support old and new executor architecture to avoid breaking changes
- first run is long, next runs are quick even if code step is updated

## Demo using `lambda` driver
### Before


https://github.com/user-attachments/assets/7f7664b4-658f-4689-8949-ea2c31131252


### After



https://github.com/user-attachments/assets/d486c8e2-f8f8-4dbd-a801-c9901e440b29
This commit is contained in:
martmull
2025-02-20 10:49:57 +01:00
committed by GitHub
parent 3f93aba5fc
commit 927b8c717e
20 changed files with 250 additions and 572 deletions

View File

@ -24,7 +24,6 @@ import {
} from 'src/engine/metadata-modules/serverless-function/serverless-function.exception';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import { serverlessFunctionGraphQLApiExceptionHandler } from 'src/engine/metadata-modules/serverless-function/utils/serverless-function-graphql-api-exception-handler.utils';
import { BuildDraftServerlessFunctionInput } from 'src/engine/metadata-modules/serverless-function/dtos/build-draft-serverless-function.input';
@UseGuards(WorkspaceAuthGuard)
@Resolver()
@ -205,22 +204,4 @@ export class ServerlessFunctionResolver {
serverlessFunctionGraphQLApiExceptionHandler(error);
}
}
@Mutation(() => ServerlessFunctionDTO)
async buildDraftServerlessFunction(
@Args('input') input: BuildDraftServerlessFunctionInput,
@AuthWorkspace() { id: workspaceId }: Workspace,
) {
try {
await this.checkFeatureFlag(workspaceId);
const { id } = input;
return await this.serverlessFunctionService.buildDraftServerlessFunction(
id,
workspaceId,
);
} catch (error) {
serverlessFunctionGraphQLApiExceptionHandler(error);
}
}
}

View File

@ -137,21 +137,12 @@ export class ServerlessFunctionService {
workspaceId,
});
if (
version === 'draft' &&
functionToExecute.syncStatus !== ServerlessFunctionSyncStatus.READY
) {
await this.buildDraftServerlessFunction(
functionToExecute.id,
workspaceId,
);
}
const resultServerlessFunction = await this.serverlessService.execute(
functionToExecute,
payload,
version,
);
const eventInput = {
action: 'serverlessFunction.executed',
payload: {
@ -200,9 +191,23 @@ export class ServerlessFunctionService {
}
}
const newVersion = await this.serverlessService.publish(
existingServerlessFunction,
);
const newVersion = existingServerlessFunction.latestVersion
? `${parseInt(existingServerlessFunction.latestVersion, 10) + 1}`
: '1';
const draftFolderPath = getServerlessFolder({
serverlessFunction: existingServerlessFunction,
version: 'draft',
});
const newFolderPath = getServerlessFolder({
serverlessFunction: existingServerlessFunction,
version: newVersion,
});
await this.fileStorageService.copy({
from: { folderPath: draftFolderPath },
to: { folderPath: newFolderPath },
});
const newPublishedVersions = [
...existingServerlessFunction.publishedVersions,
@ -264,7 +269,6 @@ export class ServerlessFunctionService {
{
name: serverlessFunctionInput.name,
description: serverlessFunctionInput.description,
syncStatus: ServerlessFunctionSyncStatus.NOT_READY,
timeoutSeconds: serverlessFunctionInput.timeoutSeconds,
},
);
@ -343,6 +347,8 @@ export class ServerlessFunctionService {
});
}
await this.serverlessService.build(createdServerlessFunction);
return this.serverlessFunctionRepository.findOneBy({
id: createdServerlessFunction.id,
});
@ -380,10 +386,6 @@ export class ServerlessFunctionService {
}),
},
});
await this.serverlessFunctionRepository.update(serverlessFunction.id, {
syncStatus: ServerlessFunctionSyncStatus.NOT_READY,
});
}
private async throttleExecution(workspaceId: string) {
@ -400,32 +402,4 @@ export class ServerlessFunctionService {
);
}
}
async buildDraftServerlessFunction(id: string, workspaceId: string) {
const functionToBuild = await this.findOneOrFail({
id,
workspaceId,
});
if (functionToBuild.syncStatus === ServerlessFunctionSyncStatus.READY) {
return functionToBuild;
}
if (functionToBuild.syncStatus === ServerlessFunctionSyncStatus.BUILDING) {
throw new ServerlessFunctionException(
'This function is currently building. Please try later',
ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_BUILDING,
);
}
await this.serverlessFunctionRepository.update(functionToBuild.id, {
syncStatus: ServerlessFunctionSyncStatus.BUILDING,
});
await this.serverlessService.build(functionToBuild, 'draft');
await this.serverlessFunctionRepository.update(functionToBuild.id, {
syncStatus: ServerlessFunctionSyncStatus.READY,
});
return functionToBuild;
}
}