refactor(bookings): move post booking side effects to background jobs#1973
refactor(bookings): move post booking side effects to background jobs#1973cal-id-actions[bot] wants to merge 2 commits into
Conversation
Greptile SummaryThis PR moves all post-booking side effects (webhooks, workflow reminders, integrations, analytics) from inline synchronous execution inside
Confidence Score: 3/5Not safe to merge as-is: the integrations service references a non-existent field The
Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant handleNewBooking
participant DB as Database
participant Dispatcher as Job Dispatcher (BullMQ)
participant W1 as Worker: Webhooks Job
participant W2 as Worker: Integrations Job
participant W3 as Worker: Scheduling Job
Client->>handleNewBooking: POST /booking
handleNewBooking->>DB: createBooking()
handleNewBooking->>handleNewBooking: buildPostCommitPayload()
Note over handleNewBooking: Only if !isDryRun
handleNewBooking->>Dispatcher: dispatch BOOKING_POST_COMMIT_WEBHOOKS
handleNewBooking->>Dispatcher: dispatch BOOKING_POST_COMMIT_INTEGRATIONS
handleNewBooking->>Dispatcher: dispatch BOOKING_POST_COMMIT_SCHEDULING
handleNewBooking-->>Client: return booking response (fast)
Note over Dispatcher,W3: Async background processing
Dispatcher->>W1: process webhooks job
W1->>W1: reconstructWebhookPayload
W1->>W1: deleteWebhookScheduledTriggers (if reschedule)
W1->>W1: scheduleTrigger (MEETING_STARTED/ENDED)
W1->>W1: handleWebhookTrigger
Dispatcher->>W2: process integrations job
W2->>W2: sendMobileNotification
W2->>W2: handleOHChatSync
W2->>W2: emitCioIdentifyForBookedHosts
W2->>W2: ensureCalIdContactFromBooking
W2->>W2: handleAnalyticsEvents
Dispatcher->>W3: process scheduling job
W3->>W3: scheduleMandatoryReminder
W3->>W3: scheduleWorkflowReminders
W3->>W3: scheduleNoShowTriggers
Reviews (1): Last reviewed commit: "Perf: Post booking side effects moved to..." | Re-trigger Greptile |
| function getMobileNotificationTitle( | ||
| tOrganizer: (key: string) => string, | ||
| payload: Pick<BookingPostCommitIntegrationsJobData, "isConfirmedByDefault" | "isRescheduleEvent"> | ||
| ) { | ||
| if (!payload.isConfirmedByDefault) { | ||
| return tOrganizer("booking_requested"); | ||
| } | ||
|
|
||
| return payload.isRescheduleEvent ? tOrganizer("booking_rescheduled") : tOrganizer("booking_created"); | ||
| } |
There was a problem hiding this comment.
isRescheduleEvent does not exist on BookingPostCommitIntegrationsJobData (or BookingPostCommitPayload); the payload only carries rescheduleUid. This causes a TypeScript compilation error via Pick, and at runtime payload.isRescheduleEvent is always undefined, so rescheduled-booking push notifications will always show "booking_created" instead of "booking_rescheduled".
| function getMobileNotificationTitle( | |
| tOrganizer: (key: string) => string, | |
| payload: Pick<BookingPostCommitIntegrationsJobData, "isConfirmedByDefault" | "isRescheduleEvent"> | |
| ) { | |
| if (!payload.isConfirmedByDefault) { | |
| return tOrganizer("booking_requested"); | |
| } | |
| return payload.isRescheduleEvent ? tOrganizer("booking_rescheduled") : tOrganizer("booking_created"); | |
| } | |
| function getMobileNotificationTitle( | |
| tOrganizer: (key: string) => string, | |
| payload: Pick<BookingPostCommitIntegrationsJobData, "isConfirmedByDefault" | "rescheduleUid"> | |
| ) { | |
| if (!payload.isConfirmedByDefault) { | |
| return tOrganizer("booking_requested"); | |
| } | |
| return payload.rescheduleUid ? tOrganizer("booking_rescheduled") : tOrganizer("booking_created"); | |
| } |
| dispatcher.dispatch({ | ||
| queue: QueueName.DEFAULT, | ||
| name: JobName.BOOKING_POST_COMMIT_WEBHOOKS, | ||
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_WEBHOOKS }, | ||
| bullmqOptions: { attempts: 1 }, | ||
| }), | ||
| dispatcher.dispatch({ | ||
| queue: QueueName.DEFAULT, | ||
| name: JobName.BOOKING_POST_COMMIT_INTEGRATIONS, | ||
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_INTEGRATIONS }, | ||
| bullmqOptions: { attempts: 1 }, | ||
| }), | ||
| dispatcher.dispatch({ | ||
| queue: QueueName.DEFAULT, | ||
| name: JobName.BOOKING_POST_COMMIT_SCHEDULING, | ||
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_SCHEDULING }, | ||
| bullmqOptions: { attempts: 1 }, | ||
| }), |
There was a problem hiding this comment.
All three post-commit jobs are dispatched with
attempts: 1, which disables retries entirely. A single transient error (Redis timeout, downstream service blip) will permanently drop webhooks, scheduling triggers, or integrations with no chance of recovery. Consider using at least 3 attempts with exponential backoff.
| dispatcher.dispatch({ | |
| queue: QueueName.DEFAULT, | |
| name: JobName.BOOKING_POST_COMMIT_WEBHOOKS, | |
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_WEBHOOKS }, | |
| bullmqOptions: { attempts: 1 }, | |
| }), | |
| dispatcher.dispatch({ | |
| queue: QueueName.DEFAULT, | |
| name: JobName.BOOKING_POST_COMMIT_INTEGRATIONS, | |
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_INTEGRATIONS }, | |
| bullmqOptions: { attempts: 1 }, | |
| }), | |
| dispatcher.dispatch({ | |
| queue: QueueName.DEFAULT, | |
| name: JobName.BOOKING_POST_COMMIT_SCHEDULING, | |
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_SCHEDULING }, | |
| bullmqOptions: { attempts: 1 }, | |
| }), | |
| dispatcher.dispatch({ | |
| queue: QueueName.DEFAULT, | |
| name: JobName.BOOKING_POST_COMMIT_WEBHOOKS, | |
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_WEBHOOKS }, | |
| bullmqOptions: { attempts: 3, backoff: { type: "exponential", delay: 5000 } }, | |
| }), | |
| dispatcher.dispatch({ | |
| queue: QueueName.DEFAULT, | |
| name: JobName.BOOKING_POST_COMMIT_INTEGRATIONS, | |
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_INTEGRATIONS }, | |
| bullmqOptions: { attempts: 3, backoff: { type: "exponential", delay: 5000 } }, | |
| }), | |
| dispatcher.dispatch({ | |
| queue: QueueName.DEFAULT, | |
| name: JobName.BOOKING_POST_COMMIT_SCHEDULING, | |
| data: { ...postCommitPayload, name: JobName.BOOKING_POST_COMMIT_SCHEDULING }, | |
| bullmqOptions: { attempts: 3, backoff: { type: "exponential", delay: 5000 } }, | |
| }), |
| export async function processBookingPostCommitWebhooks(job: Job<BookingPostCommitWebhooksJobData>) { | ||
| const ctx = createBullWorkflowContext(job); | ||
| await bookingPostCommitWebhooksService(ctx, job.data); | ||
| } |
There was a problem hiding this comment.
The apps/worker/AGENTS.md conventions require every processor to catch SleepSignal and return rather than rethrow. The three new processors omit this pattern entirely. If ctx.run() ever throws a SleepSignal internally, the job would fail instead of being paused and retried. The same gap applies to the other two processor files.
554e8e0 to
7cc5155
Compare
e54ae78 to
c7f1153
Compare
c7f1153 to
6270a41
Compare
Summary
Refactored the booking post-commit side effects to be handled asynchronously via background jobs, improving performance and reliability.
Changes
Testing Notes