Skip to main content

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:
  1. Save submission to database
  2. Sync to Airtable
  3. Send confirmation email
  4. Fire webhooks
  5. Enrich with Plaid data
If any step fails synchronously, the applicant sees an error—even though their data was saved. This creates support tickets and anxiety. With async processing: The applicant sees success in ~300ms. Integrations process in the background.

The async_operations Table

The queue is a database table, not an external service like Redis or SQS:

Operation Types

Status Lifecycle


Enqueueing Operations

The enqueueOperation function adds jobs to the queue:

Convenience Functions


Queue Processing

A cron-triggered API route processes the queue:

Claiming Operations

The claim_async_operation function uses atomic updates to prevent double-processing:
This ensures only one processor handles each operation, even with concurrent workers.

Retry Strategy

Failed operations retry with exponential backoff:
After max_attempts, the operation moves to dead status.

Error History

Each failure is recorded:
This helps debug persistent failures.

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:
  1. Transactional consistency — Enqueue in same transaction as submission
  2. No extra infrastructure — One less service to manage
  3. Easy querying — SQL for debugging and monitoring
  4. Persistence — Survives restarts without configuration
  5. ACID guarantees — Claims are atomic, no lost messages
For our volume (thousands of submissions/day), PostgreSQL handles it easily.

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 in processing status. A cleanup job resets stale processing operations:

Webhooks

Webhook delivery and HMAC signing

Background Jobs

Cron-triggered processing