Messaging
Brand Protect moves real-time data over Redis pub/sub (Python → Rails) and ActionCable (Rails → browser).
Redis pub/sub
Section titled “Redis pub/sub”The Python service publishes onto Redis channels; the Rails scan_db_consumer thread (in config/initializers/scan_db_consumer.rb) subscribes to them. All channels are prefixed with brand_protect_cable:.
| Channel | Payload | Consumed by |
|---|---|---|
scan_db_updates |
scan status / per-stage progress | process_scan_update |
scan_findings |
initial finding batch + deltas | process_initial_findings, process_findings_deltas |
domain_profiles |
owned-domain enrichment results | process_domain_profile |
social_profiles |
social-handle enrichment results | process_social_profile |
social_findings |
initial social batch + deltas | process_initial_social_findings, process_social_findings_deltas |
In addition, Python publishes a per-scan event stream that Rails relays to the browser.
What the consumer does
Section titled “What the consumer does”process_scan_update:
- merges stage progress into
scan_runs.stage_states; - broadcasts ActionCable
scan_<id>“progress” messages; - maintains the Redis active-scan key (
scan:active:<id>, TTL 1 hour); - on terminal status: sets
completed_at, writes the audit event (scan_completed/scan_failed/scan_cancelled), and enqueuesReportGenerationJob(completed) orWebhookDeliveryJob.
process_initial_findings / process_findings_deltas upsert Finding rows — the initial batch is keyed by original_domain, deltas are matched by domain.
process_domain_profile / process_social_profile upsert enrichment results with generation-staleness guards (the profile carries an enrichment_generation; stale results are dropped). When a domain profile completes, deferred scans are dispatched.
process_initial_social_findings / process_social_findings_deltas upsert SocialFinding rows keyed by (platform, handle).
ActionCable
Section titled “ActionCable”ScanChannel (app/channels/scan_channel.rb) streams scan_<id> events to the scan owner’s browser. The dashboard controller also broadcasts a cancel command on a controls channel when a scan is stopped.
Browser fallback
Section titled “Browser fallback”The dashboard does not depend solely on WebSockets: scan_monitor_controller.js also polls GET /dashboard/status every 2 seconds and reconciles the table state, so the UI converges even if the cable drops.
Wiring
Section titled “Wiring”REDIS_URL(defaultredis://redis:6379/1) configures the connection for both publisher and consumer.- The Rails consumer subscribes in a background thread at boot (
config/initializers/scan_db_consumer.rb). - Production uses Solid Cable for ActionCable storage; the stream itself is Redis-backed pub/sub.
See Redis channels for the full channel reference.