diff --git a/backend/src/services/livekit-webhook.service.ts b/backend/src/services/livekit-webhook.service.ts index d3523d8..92aa7ed 100644 --- a/backend/src/services/livekit-webhook.service.ts +++ b/backend/src/services/livekit-webhook.service.ts @@ -155,7 +155,7 @@ export class LivekitWebhookService { return; } - await this.openViduWebhookService.sendMeetingStartedWebhook(meetRoom); + this.openViduWebhookService.sendMeetingStartedWebhook(meetRoom); } catch (error) { this.logger.error('Error sending meeting started webhook:', error); } @@ -181,22 +181,18 @@ export class LivekitWebhookService { this.logger.info(`Processing room_finished event for room: ${roomName}`); + this.openViduWebhookService.sendMeetingEndedWebhook(meetRoom); + + const tasks = []; + if (meetRoom.markedForDeletion) { // If the room is marked for deletion, we need to delete it this.logger.info(`Deleting room ${roomName} after meeting finished because it was marked for deletion`); - await this.roomService.bulkDeleteRooms([roomName], true); + tasks.push(this.roomService.bulkDeleteRooms([roomName], true)); } - const results = await Promise.allSettled([ - this.recordingService.releaseRecordingLockIfNoEgress(roomName), - this.openViduWebhookService.sendMeetingEndedWebhook(meetRoom) - ]); - - results.forEach((result) => { - if (result.status === 'rejected') { - this.logger.error(`Error processing room_finished event: ${result.reason}`); - } - }); + tasks.push(this.recordingService.releaseRecordingLockIfNoEgress(roomName)); + await Promise.all(tasks); } catch (error) { this.logger.error(`Error handling room finished event: ${error}`); } @@ -236,13 +232,11 @@ export class LivekitWebhookService { // Send webhook notification switch (webhookAction) { case 'started': - specificTasks.push( - this.storageService.archiveRoomMetadata(roomId), - this.openViduWebhookService.sendRecordingStartedWebhook(recordingInfo) - ); + specificTasks.push(this.storageService.archiveRoomMetadata(roomId)); + this.openViduWebhookService.sendRecordingStartedWebhook(recordingInfo); break; case 'updated': - specificTasks.push(this.openViduWebhookService.sendRecordingUpdatedWebhook(recordingInfo)); + this.openViduWebhookService.sendRecordingUpdatedWebhook(recordingInfo); if (recordingInfo.status === MeetRecordingStatus.ACTIVE) { // Send system event for active recording with the aim of cancelling the cleanup timer @@ -256,10 +250,8 @@ export class LivekitWebhookService { break; case 'ended': - specificTasks.push( - this.openViduWebhookService.sendRecordingEndedWebhook(recordingInfo), - this.recordingService.releaseRecordingLockIfNoEgress(roomId) - ); + specificTasks.push(this.recordingService.releaseRecordingLockIfNoEgress(roomId)); + this.openViduWebhookService.sendRecordingEndedWebhook(recordingInfo); break; } diff --git a/backend/src/services/openvidu-webhook.service.ts b/backend/src/services/openvidu-webhook.service.ts index b5ad544..7351ab8 100644 --- a/backend/src/services/openvidu-webhook.service.ts +++ b/backend/src/services/openvidu-webhook.service.ts @@ -18,44 +18,96 @@ export class OpenViduWebhookService { @inject(MeetStorageService) protected globalPrefService: MeetStorageService ) {} - async sendMeetingStartedWebhook(room: MeetRoom) { - try { - await this.sendWebhookEvent(MeetWebhookEventType.MEETING_STARTED, room); - } catch (error) { - this.logger.error(`Error sending meeting started webhook: ${error}`); - } + /** + * Sends a webhook notification when a meeting has started. + * + * This method triggers a background webhook event to notify external systems + * that a meeting session has begun for the specified room. + * + * @param room - The meeting room object containing room details + */ + sendMeetingStartedWebhook(room: MeetRoom) { + this.sendWebhookEventInBackground(MeetWebhookEventType.MEETING_STARTED, room, `Room ID: ${room.roomId}`); } - async sendMeetingEndedWebhook(room: MeetRoom) { - try { - await this.sendWebhookEvent(MeetWebhookEventType.MEETING_ENDED, room); - } catch (error) { - this.logger.error(`Error sending meeting ended webhook: ${error}`); - } + /** + * Sends a webhook notification when a meeting has ended. + * + * This method triggers a background webhook event to notify external systems + * that a meeting session has concluded for the specified room. + * + * @param room - The MeetRoom object containing details of the ended meeting + */ + sendMeetingEndedWebhook(room: MeetRoom) { + this.sendWebhookEventInBackground(MeetWebhookEventType.MEETING_ENDED, room, `Room ID: ${room.roomId}`); } - async sendRecordingStartedWebhook(recordingInfo: MeetRecordingInfo) { - try { - await this.sendWebhookEvent(MeetWebhookEventType.RECORDING_STARTED, recordingInfo); - } catch (error) { - this.logger.error(`Error sending recording started webhook: ${error}`); - } + /** + * Sends a webhook event notification when a recording has started. + * + * This method triggers a background webhook event to notify external systems + * that a meeting recording has been initiated. + * + * @param recordingInfo - The recording information containing details about the started recording + */ + sendRecordingUpdatedWebhook(recordingInfo: MeetRecordingInfo) { + this.sendWebhookEventInBackground( + MeetWebhookEventType.RECORDING_UPDATED, + recordingInfo, + `Recording ID: ${recordingInfo.recordingId}` + ); } - async sendRecordingUpdatedWebhook(recordingInfo: MeetRecordingInfo) { - try { - await this.sendWebhookEvent(MeetWebhookEventType.RECORDING_UPDATED, recordingInfo); - } catch (error) { - this.logger.error(`Error sending recording updated webhook: ${error}`); - } + /** + * Sends a webhook notification when a recording has started. + * + * This method triggers a background webhook event to notify external services + * that a meeting recording has begun. The webhook includes the recording + * information and uses the recording ID for identification purposes. + * + * @param recordingInfo - The recording information containing details about the started recording + */ + sendRecordingStartedWebhook(recordingInfo: MeetRecordingInfo) { + this.sendWebhookEventInBackground( + MeetWebhookEventType.RECORDING_STARTED, + recordingInfo, + `Recording ID: ${recordingInfo.recordingId}` + ); } - async sendRecordingEndedWebhook(recordingInfo: MeetRecordingInfo) { - try { - await this.sendWebhookEvent(MeetWebhookEventType.RECORDING_ENDED, recordingInfo); - } catch (error) { - this.logger.error(`Error sending recording ended webhook: ${error}`); - } + /** + * Sends a webhook notification when a recording has ended. + * + * This method triggers a background webhook event to notify external systems + * that a meeting recording has completed. + * + * @param recordingInfo - The recording information containing details about the ended recording + */ + sendRecordingEndedWebhook(recordingInfo: MeetRecordingInfo) { + this.sendWebhookEventInBackground( + MeetWebhookEventType.RECORDING_ENDED, + recordingInfo, + `Recording ID: ${recordingInfo.recordingId}` + ); + } + + /** + * Sends a webhook event asynchronously in the background without blocking the main execution flow. + * If the webhook fails, logs a warning message with the error details and optional context information. + * + * @param event - The type of webhook event to send + * @param payload - The data payload to include with the webhook event + * @param context - Optional context string to include in error messages for debugging purposes + */ + protected sendWebhookEventInBackground( + event: MeetWebhookEventType, + payload: MeetWebhookPayload, + context?: string + ): void { + this.sendWebhookEvent(event, payload).catch((error) => { + const contextInfo = context ? ` (${context})` : ''; + this.logger.warn(`Background webhook ${event} failed${contextInfo}: ${error}`); + }); } protected async sendWebhookEvent(event: MeetWebhookEventType, payload: MeetWebhookPayload) {