From 24fa479cbfa43827f14e994deb4abead1aa28287 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Fri, 20 Jun 2025 14:42:25 +0200 Subject: [PATCH] Fix webhook size too big (#12749) --- .../services/api-event-emitter.service.ts | 2 +- .../listeners/entity-events-to-db.listener.ts | 16 ++++++++++++++-- .../webhook/jobs/call-webhook-jobs.job.ts | 18 ++++++++---------- .../modules/webhook/jobs/call-webhook.job.ts | 2 -- .../object-record-event-for-webhook.type.ts | 10 ++++++++++ 5 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 packages/twenty-server/src/modules/webhook/types/object-record-event-for-webhook.type.ts diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts index 931d246f5..8cd0e192f 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service.ts @@ -6,8 +6,8 @@ import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metad import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { objectRecordChangedValues } from 'src/engine/core-modules/event-emitter/utils/object-record-changed-values'; -import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate'; +import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; @Injectable() export class ApiEventEmitterService { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts index 726e0dbc5..70c969856 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/listeners/entity-events-to-db.listener.ts @@ -17,6 +17,7 @@ import { SubscriptionsJob } from 'src/engine/subscriptions/subscriptions.job'; import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { UpsertTimelineActivityFromInternalEvent } from 'src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job'; import { CallWebhookJobsJob } from 'src/modules/webhook/jobs/call-webhook-jobs.job'; +import { ObjectRecordEventForWebhook } from 'src/modules/webhook/types/object-record-event-for-webhook.type'; @Injectable() export class EntityEventsToDbListener { @@ -66,15 +67,26 @@ export class EntityEventsToDbListener { (event) => event.objectMetadata?.isAuditLogged, ); + const batchEventEventsForWebhook: ObjectRecordEventForWebhook[] = + batchEvent.events.map((event) => ({ + ...event, + objectMetadata: { + id: event.objectMetadata.id, + nameSingular: event.objectMetadata.nameSingular, + }, + })); + await Promise.all([ this.subscriptionsQueueService.add>( SubscriptionsJob.name, batchEvent, { retryLimit: 3 }, ), - this.webhookQueueService.add>( + this.webhookQueueService.add< + WorkspaceEventBatch + >( CallWebhookJobsJob.name, - batchEvent, + { ...batchEvent, events: batchEventEventsForWebhook }, { retryLimit: 3, }, diff --git a/packages/twenty-server/src/modules/webhook/jobs/call-webhook-jobs.job.ts b/packages/twenty-server/src/modules/webhook/jobs/call-webhook-jobs.job.ts index d56ea2607..9a47408fa 100644 --- a/packages/twenty-server/src/modules/webhook/jobs/call-webhook-jobs.job.ts +++ b/packages/twenty-server/src/modules/webhook/jobs/call-webhook-jobs.job.ts @@ -1,14 +1,12 @@ -import { Logger } from '@nestjs/common'; - import { isDefined } from 'twenty-shared/utils'; import { ArrayContains } from 'typeorm'; -import { ObjectRecordEvent } from 'src/engine/core-modules/event-emitter/types/object-record-event.event'; import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator'; import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator'; import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service'; +import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event.type'; import { @@ -17,11 +15,10 @@ import { } from 'src/modules/webhook/jobs/call-webhook.job'; import { WebhookWorkspaceEntity } from 'src/modules/webhook/standard-objects/webhook.workspace-entity'; import { removeSecretFromWebhookRecord } from 'src/utils/remove-secret-from-webhook-record'; +import { ObjectRecordEventForWebhook } from 'src/modules/webhook/types/object-record-event-for-webhook.type'; @Processor(MessageQueue.webhookQueue) export class CallWebhookJobsJob { - private readonly logger = new Logger(CallWebhookJobsJob.name); - constructor( @InjectMessageQueue(MessageQueue.webhookQueue) private readonly messageQueueService: MessageQueueService, @@ -30,7 +27,7 @@ export class CallWebhookJobsJob { @Process(CallWebhookJobsJob.name) async handle( - workspaceEventBatch: WorkspaceEventBatch, + workspaceEventBatch: WorkspaceEventBatch, ): Promise { // If you change that function, double check it does not break Zapier // trigger in packages/twenty-zapier/src/triggers/trigger_record.ts @@ -56,10 +53,11 @@ export class CallWebhookJobsJob { for (const eventData of workspaceEventBatch.events) { const eventName = workspaceEventBatch.name; - const objectMetadata = { - id: eventData.objectMetadata.id, - nameSingular: eventData.objectMetadata.nameSingular, - }; + const objectMetadata: Pick = + { + id: eventData.objectMetadata.id, + nameSingular: eventData.objectMetadata.nameSingular, + }; const workspaceId = workspaceEventBatch.workspaceId; const record = 'after' in eventData.properties && isDefined(eventData.properties.after) diff --git a/packages/twenty-server/src/modules/webhook/jobs/call-webhook.job.ts b/packages/twenty-server/src/modules/webhook/jobs/call-webhook.job.ts index f2b0da0dc..bbb964968 100644 --- a/packages/twenty-server/src/modules/webhook/jobs/call-webhook.job.ts +++ b/packages/twenty-server/src/modules/webhook/jobs/call-webhook.job.ts @@ -1,5 +1,4 @@ import { HttpService } from '@nestjs/axios'; -import { Logger } from '@nestjs/common'; import crypto from 'crypto'; @@ -26,7 +25,6 @@ export type CallWebhookJobData = { @Processor(MessageQueue.webhookQueue) export class CallWebhookJob { - private readonly logger = new Logger(CallWebhookJob.name); constructor( private readonly httpService: HttpService, private readonly auditService: AuditService, diff --git a/packages/twenty-server/src/modules/webhook/types/object-record-event-for-webhook.type.ts b/packages/twenty-server/src/modules/webhook/types/object-record-event-for-webhook.type.ts new file mode 100644 index 000000000..e953814c2 --- /dev/null +++ b/packages/twenty-server/src/modules/webhook/types/object-record-event-for-webhook.type.ts @@ -0,0 +1,10 @@ +import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; + +import { ObjectRecordEvent } from 'src/engine/core-modules/event-emitter/types/object-record-event.event'; + +export type ObjectRecordEventForWebhook = Omit< + ObjectRecordEvent, + 'objectMetadata' +> & { + objectMetadata: Pick; +};