Workers
Background processes that handle asynchronous payment execution, monitoring, and delivery.
Table of contents
Overview
The worker service runs four concurrent background processes. They operate independently and communicate through the shared PostgreSQL database and Redis queue.
Execution Worker
Type: BullMQ consumer
Queue: payment-execution
Processes payment execution jobs enqueued by the API service.
Flow
- Receive job with
paymentIntentId - Load payment intent from database
- Validate status is
route_selected - Load chain adapter for the selected chain
- Call
buildAndSendTransfer()to broadcast the transaction - Create a
payment_attemptrecord with the transaction ID - Update payment intent status to
broadcasted - Create a
debitledger entry
Error Handling
On failure:
- Payment intent status set to
failed - Reserved balance released via
releaseledger entry - Treasury available balance restored
payment.failedwebhook event created
Retry Configuration
| Setting | Value |
|---|---|
| Max attempts | 3 |
| Backoff type | Exponential |
| Initial delay | 5,000 ms |
Confirmation Worker
Type: Interval-based polling Interval: 15 seconds
Monitors broadcasted transactions for on-chain finality.
Flow
- Query all payment attempts with status
broadcasted - For each attempt, call
checkConfirmation()on the chain adapter - If confirmed:
- Update attempt status to
confirmed - Update payment intent status to
settled - Record actual fee via
feeledger entry - Update treasury: release reserved, deduct available
- Create
payment.settledwebhook event
- Update attempt status to
- If not confirmed and older than 10 minutes:
- Move payment intent to
manual_reviewstatus - Create
payment.manual_reviewwebhook event
- Move payment intent to
Stuck Transaction Detection
Transactions that remain unconfirmed for more than 10 minutes are flagged for manual review. This catches scenarios like:
- Dropped transactions
- Extreme network congestion
- RPC provider issues
Webhook Worker
Type: Interval-based polling Interval: 5 seconds
Delivers webhook events to merchant endpoints.
Flow
- Query
webhook_eventswheredelivered = falseandattempts < 5 - For each event:
- Load merchant’s
webhook_url - Send HTTPS POST with JSON payload
- Include HMAC-SHA256 signature header
- Load merchant’s
- On success: mark as
delivered = true - On failure: increment
attempts, updatelast_attempt_at
Delivery Guarantees
| Property | Value |
|---|---|
| Delivery model | At-least-once |
| Max attempts | 5 |
| Signature algorithm | HMAC-SHA256 |
Metrics Collector
Type: Interval-based polling
Interval: Configurable (METRICS_INTERVAL_MS, default 15,000 ms)
Collects real-time health metrics from each chain adapter.
Flow
- For each registered chain adapter:
- Call
getHealthMetrics() - Derive health status from raw metrics
- Insert a
chain_health_snapshotrecord
- Call
- On adapter failure:
- Insert an
unhealthysnapshot as a fallback - Routing engine will deprioritize or skip this chain
- Insert an
Health Status Logic
if (rpc_error_rate > 0.30 || congestion_score > 0.80) → unhealthy
if (rpc_error_rate > 0.10 || congestion_score > 0.50) → degraded
else → healthy
Collected Metrics
| Metric | Description | Used By |
|---|---|---|
avg_confirmation_seconds |
Mean block confirmation time | Latency scoring |
rpc_error_rate |
Fraction of failed RPC calls | Reliability scoring, health status |
p95_latency_ms |
95th percentile RPC latency | Monitoring |
congestion_score |
Network congestion (0-1) | Health status |
estimated_fee_usd |
Current fee estimate in USD | Fee scoring |