Files
mozo-backend/docs/broadcasting-migration.md
T
root 1f52448253 feat(broadcasting): add ActionCable adapter + fix model broadcast anti-pattern
- Add Mozo::Broadcaster::ActionCable as drop-in Faye replacement
- Fix model_broadcast.rb: delegate to Mozo directly instead of
  ApplicationController.new (memory-unsafe anti-pattern)
- Add Broadcastable concern for clean model-side broadcasting
- ActionCable config: async adapter, cable.yml, WebSocket endpoint
- MozoChannel with per-entity authorization (user/supplier/employee)
- Connection auth via auth_token (matches existing auth pattern)
- Mount /cable WebSocket in routes
- Add broadcasting-migration.md with Faye→ActionCable guide
2026-05-17 15:25:49 +02:00

2.5 KiB

Broadcasting: Faye → ActionCable Migration Guide

Current state

Model (SimplyStored::Couch)
  → ApplicationController.new.broadcast_user   # ⚠️ anti-pattern
    → Mozo.broadcast_user
      → Mozo::Broadcaster::Faye.new.broadcast  # HTTP POST to Faye
        → Faye server (Thin, port 9296)
          → WebSocket → browser clients

Target state

Model (Broadcastable concern)
  → Mozo.broadcast_user
    → Mozo::Broadcaster::ActionCable.new.broadcast  # in-process async
      → ActionCable (Rails built-in)
        → WebSocket → browser clients

What this branch adds

File Purpose
lib/mozo/broadcaster/action_cable.rb Drop-in ActionCable broadcaster adapter
config/cable.yml ActionCable configuration (async for single-server)
app/channels/application_cable/connection.rb WebSocket auth via auth_token
app/channels/mozo_channel.rb Channel authorization for user/supplier/employee
app/models/concerns/broadcastable.rb Clean module for models (replaces old monkey-patch)
config/routes.rb Mounts /cable WebSocket endpoint
config/initializers/model_broadcast.rb Fixed: delegates to Mozo directly (no more ApplicationController.new)

How to switch

1. Server (one-line change)

In config/initializers/mozo_settings.rb, change:

# Mozo.broadcaster = Mozo::Broadcaster::Faye.new  # old
Mozo.broadcaster = Mozo::Broadcaster::ActionCable.new  # new

2. Client (mozo-user / mozo-supplier)

Old Faye client (conceptual):

var client = new Faye.Client('https://events.mozo.bar/faye');
client.subscribe('/user/123', function(msg) { ... });

New ActionCable client:

// Using @rails/actioncable npm package
import { createConsumer } from "@rails/actioncable";

const consumer = createConsumer(
  `wss://mozo.bar/cable?auth_token=${authToken}`
);

consumer.subscriptions.create(
  { channel: "MozoChannel", id: "user_123" },
  {
    received(data) {
      // data = { event: "list_closed", data: { id: 42 } }
      handleEvent(data.event, data.data);
    }
  }
);

3. Remove Faye

Once stable:

  • Remove gem 'faye' from Gemfile
  • Remove faye/ directory
  • Remove nginx events.mozo.bar vhost
  • Stop the Faye Thin process

Benefits

  • No extra process — ActionCable runs inside Puma
  • Asyncbroadcast is non-blocking
  • Simpler deploys — one less service to manage
  • WebSocket native — no long-polling fallback complexity
  • Rails auth — cookies/sessions work automatically