Checkout & Payment Webhook Performance
Checkout went from 5–7 seconds to about half a second, and a paid status no longer waits on analytics.
- Request
- Payment
- Deploy
- Event
- AI
Context
Every order triggers emails, WhatsApp messages, subscriptions, and analytics events, and the order page polls its status every 3 seconds right after payment.
Problem
Checkout took 5–7 seconds from clicking Pay to seeing payment instructions: the request sent the confirmation email and WhatsApp message synchronously, and order endpoints loaded full entity graphs with N+1 queries. Later, the payment webhooks from Midtrans and Xendit still called Mixpanel and GA/BigQuery synchronously in one shared finish-payment step, with a new HTTP client per GA call. Every payment spent at least 327 ms there (median 521 ms), 1 in 100 took over 10 seconds, and the slowest took 139 seconds.
What I did
- Measured the checkout and webhook paths step by step: gateway calls, notifications, analytics, database queries, and frontend polling.
- Made the order-confirmation email and WhatsApp messages asynchronous, so checkout returns as soon as the gateway responds.
- Fixed N+1 queries on order history and the order-status lookup with JOIN FETCH and lazy associations, added a DTO projection and an index for order lists, and tuned the Hikari connection pool.
- Moved Mixpanel and GA/BigQuery calls out of the shared finish-payment step, so every Midtrans and Xendit channel benefits.
- Gave background work a bounded executor (8–32 threads, queue of 500, caller-runs when full) and the analytics integration one shared OkHttp client with 5-second connect and 10-second read timeouts.
Next case study
Kubernetes Platform: CI/CD & Monitoring for 15+ Applications