track serverless functions executions (#7963)

Solves: 
https://github.com/twentyhq/private-issues/issues/74

**TLDR**
When a serverless function is executed, the result is send to tinybird
event data source.

**In order to test:**

1. Set ANALYTICS_ENABLED to true
2. Put your TINYBIRD_INGEST_TOKEN from twenty_event_playground in your
.env file
3.  Don't forget to run the worker
4. Create your serverless function and run it
5. The event should be logged on the event datasource in
twenty_event_playground

**What is the structure of the payload of a serverless function event?**

Here are two examples of the payload:

`{"duration":37,"status":"SUCCESS","functionId":"a9fd87c0-af86-4e17-be3a-a6d3d961678a","functionName":"testingFunction"}`

`

{"duration":34,"status":"ERROR","errorType":"ReferenceError","functionId":"a9fd87c0-af86-4e17-be3a-a6d3d961678a","functionName":"testingFunction"}`

**Possible improvments**

- Change the status(str) to success(bool) 
- Enrich data in the payload
This commit is contained in:
Ana Sofia Marin Alexandre
2024-10-22 12:51:51 -03:00
committed by GitHub
parent 430644448a
commit 29bd4e5f2d
2 changed files with 29 additions and 1 deletions

View File

@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
import { FileModule } from 'src/engine/core-modules/file/file.module';
@ -18,6 +19,7 @@ import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverles
TypeOrmModule.forFeature([FeatureFlagEntity], 'core'),
FileModule,
ThrottlerModule,
AnalyticsModule,
],
providers: [ServerlessFunctionService, ServerlessFunctionResolver],
exports: [ServerlessFunctionService],

View File

@ -9,6 +9,7 @@ import { Repository } from 'typeorm';
import { FileStorageExceptionCode } from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception';
import { ServerlessExecuteResult } from 'src/engine/core-modules/serverless/drivers/interfaces/serverless-driver.interface';
import { AnalyticsService } from 'src/engine/core-modules/analytics/analytics.service';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { readFileContent } from 'src/engine/core-modules/file-storage/utils/read-file-content';
@ -41,6 +42,7 @@ export class ServerlessFunctionService {
private readonly serverlessFunctionRepository: Repository<ServerlessFunctionEntity>,
private readonly throttlerService: ThrottlerService,
private readonly environmentService: EnvironmentService,
private readonly analyticsService: AnalyticsService,
) {}
async findManyServerlessFunctions(where) {
@ -115,7 +117,31 @@ export class ServerlessFunctionService {
);
}
return this.serverlessService.execute(functionToExecute, payload, version);
const resultServerlessFunction = await this.serverlessService.execute(
functionToExecute,
payload,
version,
);
const eventInput = {
action: 'serverlessFunction.executed',
payload: {
duration: resultServerlessFunction.duration,
status: resultServerlessFunction.status,
...(resultServerlessFunction.error && {
errorType: resultServerlessFunction.error.errorType,
}),
functionId: functionToExecute.id,
functionName: functionToExecute.name,
},
};
this.analyticsService.create(
eventInput,
'serverless-function',
workspaceId,
);
return resultServerlessFunction;
}
async publishOneServerlessFunction(id: string, workspaceId: string) {