Event-Driven Pipeline
How Critique ingests GitHub webhooks, deduplicates deliveries, and choreographs async review pipelines via QStash.
Critique’s GitHub integration is built around an extremely resilient, asynchronous event-driven architecture. This ensures that the system handles spikes in GitHub webhook traffic without timing out, losing events, or double-processing PRs.
1. Webhook Ingestion & Deduplication
When a webhook hits the /api/github/webhooks endpoint, the immediate goal is to safely accept the payload and return a 202 Accepted to GitHub as fast as possible.
- Deduplication: The system extracts the
X-GitHub-Deliveryheader and checks the database for an existingDeliveryEventwith this ID. If it exists and its status isRECEIVED,VALIDATED,QUEUED, orENQUEUED, Critique updates the status toDEDUPEDand immediately stops processing. - Event Lifecycle Tracking: The lifecycle of a delivery is rigorously tracked via database statuses:
RECEIVED→VALIDATED→QUEUED(when sent to QStash) →PROCESSING(when QStash hits the handler) →COMPLETED(orIGNORED/FAILED).
2. QStash Choreography
To prevent server timeouts and handle rate limits gracefully, Critique relies on Upstash QStash as its asynchronous task queue.
The lifecycle of a PR review webhook follows a strict choreography:
- Ingestion: GitHub sends a
pull_requestwebhook. Critique verifies the payload signature, stores it as aDeliveryEvent, pushes agithub/webhook.receivedmessage to QStash, and returns202 Accepted. - Routing: QStash calls the
process-deliveryendpoint. The processor looks up the saved delivery, extracts PR metadata (base SHA, head SHA, clone URL), and synchronously syncs the GitHub App installation record. - Review Queueing: The delivery processor calls
queuePullRequestReview(...)to create a newReviewRunrecord in the database. - Pipeline Triggering: The delivery processor immediately sends a second QStash message:
review/run.requestedcontaining thereviewRunId. The delivery is then marked asCOMPLETED. - Execution: QStash consumes the
review/run.requestedmessage, invoking the actual AI review pipeline (/api/qstash/review-run) to fetch code diffs, generate comments, and post them back to the GitHub PR.
3. Delivery Replay
Because it uses QStash, failed webhook deliveries (e.g., resulting in a FAILED state due to network errors) can be retried. The process-delivery handler explicitly tracks and increments an attemptCount field in the database every time a delivery is processed, safely logging error messages if processing throws an exception.
4. Lazy Syncing & Active Indexing
Installation and repository state is kept highly eventually-consistent using two key strategies:
- Lazy Syncing: Every single processed webhook (
pull_request,push,check_run, etc.) automatically callssyncInstallationRecord()before doing its primary work. This ensures the database installation record is never stale, even if a dedicatedinstallationwebhook was previously dropped. - Active Indexing: When an
installation(created) orinstallation_repositories(repositories added) event occurs, the system doesn't just sync the record. It actively gathers the newly added repositories and callsenqueueAutoIndexesForInstallation. This pushes jobs to a background QStash worker to clone the repositories and build the vector indexes (embeddings) for the codebase. Deleted installations or removed repositories bypass this intensive indexing step.