# Migration 019: PostgreSQL NOTIFY Architecture ## System Overview ``` ┌─────────────────────────────────────────────────────────────────────┐ │ PostgreSQL NOTIFY/LISTEN System │ │ Migration 019 │ └─────────────────────────────────────────────────────────────────────┘ Database Tables ┌───────────────────────────────────────────────────────────────────────┐ │ │ │ config_entries model_config RBAC Tables │ │ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │ │ │ key: string │ │ name: str │ │ roles │ │ │ │ value: text │ │ version: str│ │ permissions │ │ │ │ ... │ │ is_active │ │ role_perms │ │ │ └─────────────┘ └─────────────┘ │ user_roles │ │ │ │ │ └──────────────┘ │ │ │ │ │ │ └─────────┼──────────────────────┼─────────────────────┼───────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ AFTER TRIGGER │ │ AFTER TRIGGER │ │ AFTER TRIGGER │ │ INSERT/UPDATE/ │ │ INSERT/UPDATE/ │ │ INSERT/UPDATE/ │ │ DELETE │ │ DELETE │ │ DELETE │ └─────────────────┘ └──────────────────┘ └──────────────────┘ │ │ │ ▼ ▼ ▼ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────┐ │ notify_config_ │ │ notify_model_ │ │ notify_ │ │ change() │ │ config_change() │ │ permission_ │ │ │ │ │ │ change() │ │ • Extract category │ │ • Extract model │ │ • Extract IDs │ │ • Route to service │ │ • Notify ML+Trading│ │ • Build payload│ │ • Build JSON │ │ • Build JSON │ │ • Notify API GW│ └────────────────────┘ └────────────────────┘ └────────────────┘ │ │ │ │ │ │ └──────────┬───────────┴─────────────────────┘ │ ▼ ┌───────────────────────┐ │ pg_notify() │ │ PostgreSQL Core │ └───────────────────────┘ │ ┌───────────────┼────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────────┐ ┌─────────────────────┐ │ Service │ │ Service │ │ Monitoring │ │ Channels │ │ Channels │ │ Channel │ └──────────┘ └──────────────┘ └─────────────────────┘ NOTIFY Channels ┌───────────────────────────────────────────────────────────────────────┐ │ │ │ config_changed_trading │ │ ├─ risk.* │ │ ├─ execution.* │ │ ├─ compliance.* │ │ └─ model_config (consumer) │ │ │ │ config_changed_backtesting │ │ ├─ backtesting.* │ │ ├─ strategy.* │ │ └─ simulation.* │ │ │ │ config_changed_ml_training │ │ ├─ ml.* │ │ ├─ training.* │ │ ├─ models.* │ │ └─ model_config (owner) │ │ │ │ config_changed_api_gateway │ │ ├─ api.* │ │ ├─ auth.* │ │ └─ gateway.* │ │ │ │ permissions_changed │ │ ├─ roles │ │ ├─ permissions │ │ ├─ role_permissions │ │ └─ user_roles │ │ │ │ config_changed_global │ │ └─ All changes (monitoring) │ │ │ └───────────────────────────────────────────────────────────────────────┘ Service Consumers ┌───────────────────────────────────────────────────────────────────────┐ │ │ │ ┌────────────────────┐ ┌────────────────────┐ │ │ │ Trading Service │ │ ML Training │ │ │ │ │ │ Service │ │ │ │ LISTEN: │ │ │ │ │ │ • config_changed_ │ │ LISTEN: │ │ │ │ trading │◄────────┤ • config_changed_ │ │ │ │ │ │ ml_training │ │ │ │ Hot-reload: │ │ │ │ │ │ • Risk limits │ │ Hot-reload: │ │ │ │ • VaR params │ │ • Model cache TTL │ │ │ │ • Model updates │ │ • Training params │ │ │ └────────────────────┘ │ • Model lifecycle │ │ │ └────────────────────┘ │ │ │ │ ┌────────────────────┐ ┌────────────────────┐ │ │ │ Backtesting │ │ API Gateway │ │ │ │ Service │ │ │ │ │ │ │ │ LISTEN: │ │ │ │ LISTEN: │ │ • permissions_ │ │ │ │ • config_changed_ │ │ changed │ │ │ │ backtesting │ │ │ │ │ │ │ │ Hot-reload: │ │ │ │ Hot-reload: │ │ • RBAC cache │ │ │ │ • Strategy params │ │ • User permissions │ │ │ │ • Simulation config│ │ • Rate limits │ │ │ └────────────────────┘ └────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ Monitoring / Admin Dashboard │ │ │ │ │ │ │ │ LISTEN: config_changed_global │ │ │ │ │ │ │ │ • All configuration changes │ │ │ │ • Real-time dashboard updates │ │ │ │ • Audit trail visualization │ │ │ └────────────────────────────────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────────────────┘ Notification Flow Example ┌───────────────────────────────────────────────────────────────────────┐ │ │ │ 1. Admin Updates Risk Limit via TLI │ │ UPDATE config_entries SET value = '200000' │ │ WHERE key = 'risk.max_daily_loss'; │ │ │ │ 2. Trigger Executes │ │ notify_config_change() function runs │ │ • Extracts category: 'risk' │ │ • Routes to service: 'trading' │ │ • Builds JSON payload │ │ │ │ 3. NOTIFY Sent to Channels │ │ pg_notify('config_changed_trading', payload) │ │ pg_notify('config_changed_global', payload) │ │ │ │ 4. Trading Service Receives Notification │ │ ConfigListener processes payload │ │ • Parses JSON │ │ • Identifies changed key │ │ • Updates in-memory config │ │ • Logs change for audit │ │ │ │ 5. Hot-Reload Complete │ │ ✓ No service restart required │ │ ✓ Change applied in <100ms │ │ ✓ Zero downtime │ │ │ └───────────────────────────────────────────────────────────────────────┘ Payload Structure (JSON) ┌───────────────────────────────────────────────────────────────────────┐ │ │ │ Config Entry Change: │ │ { │ │ "operation": "UPDATE", │ │ "table": "config_entries", │ │ "key": "risk.max_daily_loss", │ │ "value": "200000", │ │ "old_value": "100000", │ │ "category": "risk", │ │ "timestamp": 1730000000.123, │ │ "id": "550e8400-e29b-41d4-a716-446655440000" │ │ } │ │ │ │ Model Config Change: │ │ { │ │ "operation": "UPDATE", │ │ "table": "model_config", │ │ "model_name": "mamba2", │ │ "version": "v1.2.3", │ │ "is_active": true, │ │ "timestamp": 1730000000.123, │ │ "id": "550e8400-e29b-41d4-a716-446655440000" │ │ } │ │ │ │ Permission Change: │ │ { │ │ "operation": "INSERT", │ │ "table": "role_permissions", │ │ "timestamp": 1730000000.123, │ │ "role_id": "550e8400-e29b-41d4-a716-446655440000", │ │ "permission_id": "660e8400-e29b-41d4-a716-446655440000", │ │ "user_id": null │ │ } │ │ │ └───────────────────────────────────────────────────────────────────────┘ Performance Characteristics ┌───────────────────────────────────────────────────────────────────────┐ │ │ │ Trigger Execution Overhead: │ │ • JSON building: ~0.1ms │ │ • String manipulation: ~0.05ms │ │ • pg_notify() call: ~0.2ms │ │ • Total per notification: ~0.35ms │ │ │ │ NOTIFY Delivery: │ │ • In-process delivery: <1ms │ │ • Network delivery: <5ms (typical LAN) │ │ • Guaranteed order: Yes (per session) │ │ • Guaranteed delivery: Only if LISTEN active │ │ │ │ Service Hot-Reload: │ │ • Notification receipt: <5ms │ │ • JSON parsing: ~0.1ms │ │ • Config update: ~1ms │ │ • Total latency: <10ms (end-to-end) │ │ │ │ Scalability: │ │ • Max concurrent listeners: Thousands │ │ • Max payload size: 8,000 bytes │ │ • Throughput: 10,000+ notifications/sec │ │ • Resource usage: Minimal (shared memory) │ │ │ └───────────────────────────────────────────────────────────────────────┘ Design Decisions ┌───────────────────────────────────────────────────────────────────────┐ │ │ │ 1. Service-Specific Channels vs. Single Channel │ │ ✓ Chosen: Service-specific channels │ │ • Reduces noise for individual services │ │ • Enables targeted cache invalidation │ │ • Improves scalability │ │ • Maintains global channel for monitoring │ │ │ │ 2. Key Prefix Routing vs. Explicit Service Field │ │ ✓ Chosen: Key prefix routing │ │ • Natural organization (risk.*, ml.*, etc.) │ │ • No additional schema changes required │ │ • Easy to understand and maintain │ │ • Flexible categorization │ │ │ │ 3. Row-Level vs. Statement-Level Triggers │ │ ✓ Chosen: Row-level (FOR EACH ROW) │ │ • Detailed change tracking │ │ • Includes old/new values │ │ • Better for audit trails │ │ • Statement-level possible for batching │ │ │ │ 4. JSON vs. Text Payloads │ │ ✓ Chosen: JSON with structured fields │ │ • Type-safe deserialization │ │ • Standard format across services │ │ • Easy to extend with new fields │ │ • Well-supported in all languages │ │ │ │ 5. Multi-Channel for Model Changes │ │ ✓ Chosen: Send to both ML and trading │ │ • ML service owns model lifecycle │ │ • Trading service consumes models │ │ • Both need immediate updates │ │ • Prevents stale model usage │ │ │ └───────────────────────────────────────────────────────────────────────┘ Future Enhancements ┌───────────────────────────────────────────────────────────────────────┐ │ │ │ Phase 1: Core Functionality (✓ Complete) │ │ • Service-specific channel routing │ │ • JSON payload structure │ │ • Multi-channel for model changes │ │ • RBAC permission notifications │ │ │ │ Phase 2: Advanced Features (Planned) │ │ • Batched notifications for bulk updates │ │ • Change history table for replay │ │ • Conditional notifications (skip no-ops) │ │ • Priority levels (critical vs. informational) │ │ │ │ Phase 3: Optimization (Future) │ │ • Compression for large payloads │ │ • Deduplication for rapid changes │ │ • Throttling for high-frequency updates │ │ • Metrics and monitoring │ │ │ └───────────────────────────────────────────────────────────────────────┘