Alert Dispatch Flow
How the system evaluates alert rules and delivers real-time in-app notifications.
Overviewβ
Alert dispatch uses a hybrid evaluation pipeline combining scheduled and event-driven triggers. Both paths use a shared IAlertRuleEvaluator for consistent business logic, and delivery is handled via SignalR with a Redis backplane for instant UI reactivity.
Hybrid Evaluation Pipelineβ
The system ensures alert rules are checked whenever relevant data changes.
- Scheduled Path (
SyncPricesJob): Runs on a cron schedule (config:WorkerSettings.Schedules.SyncPrices). Scans symbols, fetches quotes, evaluates rules, persists notifications, and pushes via SignalR. - Event Path (
MarketPriceAlertHandler): Triggered by SQS events (EventType:inventoryalert.pricing.price-drop.v1) for a specific symbol + price. - Holdings Path (
LowHoldingsHandler): Triggered by SQS events (EventType:inventoryalert.inventory.stock-low.v1) when a userβs holdings drop below a threshold.
Shared Evaluator Logic (IAlertRuleEvaluator)β
Real-Time Delivery (SignalR)β
SignalR provides an instant push architecture:
- Hub Host:
InventoryAlert.Apihosts theNotificationHubat/hubs/notifications. - The Signal: When the Worker (producer) identifies a breach, it calls
NotifyAsyncon theIAlertNotifier. - The Relay: The notifier publishes the
NotificationResponseto the Redis Backplane. - The Push: Redis relays the message to all Api instances. The instance holding the user's connection pushes the JSON payload over the WebSocket tunnel.
- The UI: The Next.js
NotificationProviderreceives the event and updates the navbar badge instantly.
Traceability & Observabilityβ
Every alert flow is traceable via a unique CorrelationId:
- API Initiated: The
X-Correlation-Idfrom the HTTP request is propagated to the SQSEventEnvelope. - Worker Context: The
IntegrationMessageRouterextracts theCorrelationIdfrom the envelope and pushes it to the SerilogLogContext. - Cross-Project Trace: Logs in Seq from both the API and Worker are grouped by this ID, allowing deterministic verification in integration tests using
SeqLogReader. - Message Metadata: Each log entry also includes
MessageIdandEventTypefor granular debugging.
Notification Schemaβ
Notifications are now categorized for better UX:
| Field | Detail |
|---|---|
| Type | Price, Holdings, System, News |
| Severity | Info, Warning, Critical |
| Status | Real-time state maintained via React Context + SignalR. |
Deduplication & Cooldownβ
To prevent "Alert Storms," the system enforces a cooldown gate:
- Key Pattern:
inventoryalert:alerts:cooldown:v1:{userId}:{ruleId} - Standard TTL: 24 hours (set by the shared
IAlertRuleEvaluator) - SQS message idempotency:
msg:processed:{messageId}(24h TTL) prevents processing the same SQS message multiple times in the native polling worker.