Queue Architecture
When an applicant submits a form, we save it immediately. Everything else—Airtable sync, email, webhooks—happens asynchronously.Form submissions are sacred. If Airtable is down or an email fails, the applicant shouldn’t see an error. Terra uses a persistent async queue to decouple submission success from integration success.
Why Async?
Consider what happens on submission:- Save submission to database
- Sync to Airtable
- Send confirmation email
- Fire webhooks
- Enrich with Plaid data
The async_operations Table
The queue is a database table, not an external service like Redis or SQS:Operation Types
| Type | Purpose | Max Attempts |
|---|---|---|
webhook | Fire webhook to external URL | 5 |
airtable_sync | Sync submission to Airtable | 3 |
email | Send email via Resend | 3 |
sms | Send SMS via Twilio | 3 |
plaid_enrichment | Fetch Plaid verification data | 3 |
notification | Combined email + SMS | 3 |
Status Lifecycle
Enqueueing Operations
TheenqueueOperation function adds jobs to the queue:
Convenience Functions
Queue Processing
A cron-triggered API route processes the queue:Claiming Operations
Theclaim_async_operation function uses atomic updates to prevent double-processing:
Retry Strategy
Failed operations retry with exponential backoff:| Attempt | Backoff | Total Wait |
|---|---|---|
| 1 | 5 min | 5 min |
| 2 | 10 min | 15 min |
| 3 | 20 min | 35 min |
| 4 | 40 min | 75 min |
| 5 | 80 min | ~2.5 hours |
max_attempts, the operation moves to dead status.
Error History
Each failure is recorded:Dead-Letter Handling
Operations that fail all retries need manual attention:Monitoring
Queue Status View
A database view summarizes queue health:Notification Statistics
Operation Payloads
Each operation type has a specific payload structure:Webhook
Airtable Sync
Notification
Why Database, Not Redis/SQS?
We use PostgreSQL instead of dedicated queue services because:- Transactional consistency — Enqueue in same transaction as submission
- No extra infrastructure — One less service to manage
- Easy querying — SQL for debugging and monitoring
- Persistence — Survives restarts without configuration
- ACID guarantees — Claims are atomic, no lost messages
Edge Cases
Duplicate Prevention
Webhook idempotency keys prevent double-delivery:Long-Running Operations
Some operations (like large Airtable syncs) may timeout. The processor sets a maximum execution time and fails gracefully:Stuck Processing
If a processor crashes mid-operation, the operation stays inprocessing status. A cleanup job resets stale processing operations: