Skip to content

Messaging

Brand Protect moves real-time data over Redis pub/sub (Python → Rails) and ActionCable (Rails → browser).

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.

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 enqueues ReportGenerationJob (completed) or WebhookDeliveryJob.

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).

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.

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.

  • REDIS_URL (default redis://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.