Skip to content

Traffic Spike Backpressure Gap Mining

Scope: migration plan for traffic spikes that must not take down booking, payment, document, settlement, notification, matching, or webhook paths. This is an operator/backend decision page only; active payment, settlement, and branch-resource workers stay untouched.

Current foundation: Compose now applies Traefik rateLimit and inFlightReq middleware to public backend, frontend, and Supabase routers; self-hosted Supabase already creates pgmq; backend has a Supabase pgmq adapter; stage env has queue/worker/backpressure SSOT; backend now centralizes workload queue names, priorities, visibility timeout, max attempts, and dead-letter names in application.platform.supabase_queue_contract; backend worker dispatch now uses application.platform.supabase_queue_worker plus the stdlib SupabasePgmqQueueAdapter to read, archive, retry by visibility timeout, and dead-letter messages; Supabase CLI migrations create every queue/dead-letter queue and service-role-only pgmq_read/pgmq_archive RPC wrappers; and otel-collector receives backend OTLP telemetry on the internal network.

LayerOSS choiceUseMigration rule
Edge load balancingTraefikHost/path routing, service load balancing, HTTP rateLimit, inFlightReq, retry, and circuitBreaker middlewares where route-safeConfigure through Docker labels and env SSOT. No host ports. Return 429 or stable degraded response before backend pool exhaustion.
Telemetry collectorOpenTelemetry CollectorVendor-neutral OTLP traces, metrics, logs, collector internal metrics, later exporter fanoutRun internally only. Backend emits OTLP gRPC. Prometheus/Grafana/Tempo/Loki remain exporter slice, not feature code dependencies.
Durable orchestrationRestateLong-running payment, document, settlement, webhook, and batch workflows with persisted progress, retry, and replayRestate owns workflow progress. Supabase remains business ledger, read model, RLS, and audit store.
Durable queueSupabase Queues / pgmqPostgres-native work queues for idempotent background jobs and burst smoothingDefault queue layer because self-hosted Supabase already owns Postgres. Enable pgmq only through migration/config proof and expose pgmq_public intentionally if Data API access is required.
Cache/rate countersValkey or RedisHot counters, short TTL locks, and request-shaping state when Postgres queue reads become too hotJustified only if shared counters exceed Postgres-friendly write rate. Existing Novu Redis is Novu-owned; do not reuse it for Sanmopia domain state without a separate service/env contract.
Stream/brokerNATS or RabbitMQHigh fan-out event streams or competing consumers beyond pgmq visibility-timeout needsDefer. Add only with measured need: cross-service event fanout, high-throughput notifications, or queue latency that pgmq cannot meet.

External baseline checked: Traefik rate limit, Traefik in-flight requests, Supabase Queues, and Restate key concepts. OpenTelemetry Collector architecture, configuration, and internal telemetry are tracked in Observability and Backpressure.

FlowSpike riskIngress behaviorQueue/workflowWorker capIdempotency keyRetry / dead letterPriority
Payment pre-registrationGateway timeout, duplicate click, payment id collisionTraefik rate limit per user/IP and low inFlightReq; backend rejects when payment queue lag is above threshold except status readsRestate payment workflow plus Supabase payment ledger; pgmq only for follow-up reconciliation tasksSmall fixed pool per provider and per payment methodpayment_id plus reservation id plus purposeProvider 5xx/timeouts retry with exponential backoff; duplicate provider success is replay; nonretryable amount/status mismatch goes operator review queueP0
Document generationXLSX/PDF render CPU spike, bundle fanout, storage pressureAccept request, return queued status, never render synchronously from operator clickpgmq render queue per artifact kind; Restate for bundle/build workflows needing multi-step recoverySeparate render workers by format; one large bundle per workerrender request code plus template version plus reservation/document snapshot hashRetry renderer/storage transient failures; dead letter after capped attempts with repair command and stored failure reasonP1
Settlement exportsMonth-end HQ/branch export burst, stale totals, long filesystem writesDashboard/export reads stay fast; export command freezes dataset then queues buildRestate export workflow using frozen Supabase snapshot; pgmq optional renderer queueOne export per branch plus small global cap for HQ bulkexport request id plus dataset revision plus formatRetry using frozen snapshot only; dead letter to settlement repair history, not recompute current totalsP1
Notification sendsBirth-info reminders, payment deadlines, campaign burstsAPI creates dispatch request and returns accepted; no direct provider send on user pathSupabase task/queue rows hand off to Novu; Restate only for business workflows that wait on notification outcomeChannel-specific caps and provider-specific rate bucketscommunication dispatch id plus business event idProvider retry/backoff in Novu plus Sanmopia dispatch event audit; dead letter requires operator replay or suppression reasonP2
Matching batchBranch-wide assignment optimizer CPU and provider travel-time lookup burstUser actions enqueue optimization; UI polls snapshot/projectionpgmq batch queue; Restate only if assignment workflow spans reservation mutation and notificationOne optimizer per branch/profile segment; travel lookup cap per provideroptimization request id plus policy version plus reservation/candidate snapshot revisionRetry deterministic compute; external travel lookup failures become partial evidence with rerun actionP1
Webhook processingKill Bill duplicate/out-of-order callbacks, provider retry stormRestricted internal Traefik route injects a callback-admission token; backend validates that token before enqueue. Kill Bill does not sign push callbacks.Append webhook inbox row in Supabase, then Restate/payment workflow consumes ordered factsSmall ordered worker pool per provider/payment idprovider event identity plus payment id, transaction id, operation, and event typeDuplicate inbox rows replay to same result; missing/invalid admission token is rejected; unrecognized state moves to dead-letter reviewP0

Every queued command or workflow start must store:

  • Stable idempotency key and request hash.
  • Actor id, actor type, branch/HQ scope, and authorization decision reference.
  • Business priority, queue name, visibility timeout, next attempt time, attempt count, max attempts, and retry class.
  • Frozen input snapshot ids, not mutable source rows.
  • Expected aggregate/read-model revision where command mutates business state.
  • Result read-model ids, public status, blocked reason, and failure reason.
  • Dead-letter row with replay policy: replay_same_input, repair_then_replay, suppress, or manual_reconcile.

Current backend workload queues:

WorkloadQueueDead-letterPriorityWorker env
SpiceDB relationship syncsanmopia_spicedb_relationshipssanmopia_spicedb_relationships_deadHighSANMOPIA_WORKER_AUTHORIZATION_SYNC_CONCURRENCY
Payment reconciliationsanmopia_payment_reconciliationsanmopia_payment_reconciliation_deadCriticalSANMOPIA_WORKER_PAYMENT_CONCURRENCY
Kill Bill webhook processingsanmopia_payment_webhook_processingsanmopia_payment_webhook_processing_deadCriticalSANMOPIA_WORKER_WEBHOOK_CONCURRENCY
Document renderingsanmopia_document_renderingsanmopia_document_rendering_deadHighSANMOPIA_WORKER_DOCUMENT_RENDER_CONCURRENCY
Settlement exportsanmopia_settlement_exportsanmopia_settlement_export_deadHighSANMOPIA_WORKER_SETTLEMENT_EXPORT_CONCURRENCY
Notification dispatchsanmopia_notification_dispatchsanmopia_notification_dispatch_deadNormalSANMOPIA_WORKER_NOTIFICATION_CONCURRENCY
Caregiver matching optimizationsanmopia_caregiver_matching_optimizationsanmopia_caregiver_matching_optimization_deadHighSANMOPIA_WORKER_MATCHING_CONCURRENCY
  • Workers scale by queue and capability, not by one generic background worker.
  • Default concurrency is explicit env SSOT per queue: SANMOPIA_WORKER_AUTHORIZATION_SYNC_CONCURRENCY, SANMOPIA_WORKER_PAYMENT_CONCURRENCY, SANMOPIA_WORKER_DOCUMENT_RENDER_CONCURRENCY, SANMOPIA_WORKER_SETTLEMENT_EXPORT_CONCURRENCY, SANMOPIA_WORKER_NOTIFICATION_CONCURRENCY, SANMOPIA_WORKER_MATCHING_CONCURRENCY, and SANMOPIA_WORKER_WEBHOOK_CONCURRENCY.
  • Worker claims must use visibility timeout or equivalent lease. Long jobs heartbeat progress through Supabase ledger/workflow rows.
  • Worker acknowledgement must archive successful source messages through pgmq; retryable failures must leave the source message leased for visibility-timeout retry; terminal or max-attempt failures must enqueue a dead-letter payload with replay policies before archiving the source message.
  • Worker startup must fail closed when queue schema, env SSOT, Restate endpoint, or Supabase service role is missing.
  • User-facing reads must prefer status projection over queue internals.

Compose already routes through Traefik labels and container expose without host ports. Next safe config slice is label-only middleware on public routers:

  • sanmopia-backend-rate-limit: per-source average/burst caps for /api.
  • sanmopia-backend-inflight: concurrent request cap before Uvicorn pool starvation.
  • sanmopia-backend-retry: only for idempotent GET status/read routes; do not retry payment mutation routes at the edge.
  • sanmopia-backend-circuit-breaker: only where current Traefik image supports the OSS HTTP middleware and the fallback behavior is tested.

Do not add proprietary API gateways, cloud queue products, or host-port shortcuts. Docker label values must come from .env.example or generated env SSOT, not inline magic numbers.

Required dashboard/read-model fields:

  • Queue depth by queue, priority, and oldest age.
  • In-flight count and worker concurrency by queue.
  • Retry count, dead-letter count, and replay count.
  • Time to accept, time to first claim, time to complete, and p95/p99 latency.
  • Traefik 429 rate, backend 503 shedding rate, provider timeout rate.
  • Restate workflow status and blocked reason projected through backend APIs.
  • Supabase ledger drift: queued item without workflow, workflow without ledger, and ready artifact without signed grant audit.
  • Trace correlation id across Traefik request, backend command, pgmq message, Restate workflow id, external provider request id, and operator repair action.
  • Add Supabase migration for pgmq availability. Current core access migration creates pgmq and sanmopia_spicedb_relationships; next migrations should add queue names per workload, not a second queue engine.
  • Define queue names, priorities, visibility timeouts, max attempts, and dead-letter queues in backend contracts and Supabase CLI migration.
  • Add backend queue worker dispatcher and Supabase pgmq read/archive adapter contract so workload processors do not reimplement ack/retry/dead-letter behavior.
  • Bind SpiceDB relationship sync processor so branch membership and branch hierarchy relationship payloads are validated, written through SpiceDBAuthorizationPort, archived on success, and dead-lettered when the payload no longer matches the relationship tuple.
  • Expose the internal service-token worker dispatch endpoint POST /internal/queue-workloads/{workloadKind}/dispatches so Cron/worker runners call one backend dispatcher instead of bespoke per-workload scripts.
  • Add worker/env backpressure SSOT to .env.example.
  • Add Traefik middleware labels for backend, frontend, and Supabase public routers with rateLimit and inFlightReq values enforced by pnpm stage:check.
  • Add internal OpenTelemetry Collector and backend OTLP env wiring.
  • Bind Kill Bill webhook processing to the shared Supabase queue worker so callbacks pass internal admission-token validation, atomically register inbox plus PGMQ handoff, and return bounded 202 outcomes: queued, duplicate, or quarantined. Worker validates/dead-letters corrupt payloads before starting payment workflow ingestion; duplicate/conflicting deliveries create no second queue message.
  • Split payment/webhook mutation routes from idempotent status/read routes before enabling edge retry.
  • Bind remaining workload-specific processors for payment reconciliation, document rendering, settlement export, notification dispatch, and caregiver matching optimization.
  • Add Prometheus/Grafana/Tempo/Loki exporters after collector smoke and retention policy are decided.
  • Add operator queue dashboard and repair/replay commands before production traffic spike testing.
  • Run spike smoke: payment duplicate clicks, document bulk render, settlement month-end export, notification burst, matching batch, and webhook replay storm.