3e4bcc80c8
- Add Mozo::Counter::Redis with same get/set/incr/decr interface - Add redis gem (~> 5.0) to Gemfile - Update cable.yml to use Redis adapter in production (shared with counters) - Document DrbCounter → Redis migration in broadcasting-migration.md - Redis installed and running on vmi3300327 - Leave Faye as current broadcaster; both switches are one-line changes DrbCounter problems solved: - In-memory → persistent (RDB + AOF) - Single-process DRb → multi-process safe Redis - Atomic INCR/DECR across Puma workers - One less custom process to manage
4.5 KiB
4.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.barvhost - Stop the Faye Thin process
Benefits
- No extra process — ActionCable runs inside Puma
- Async —
broadcastis non-blocking - Simpler deploys — one less service to manage
- WebSocket native — no long-polling fallback complexity
- Rails auth — cookies/sessions work automatically
Counter: DrbCounter → Redis Migration
Current state
Supplier::Counters (app/models/supplier/counters.rb)
→ Mozo::Counter.incr/decr/get/set
→ Mozo::Counter.connection (Mozo::DrbCounter.object)
→ DRb → druby://localhost:9022
→ InMemoryQCounter (separate Ruby process)
→ on startup: reloads counts from CouchDB
→ in-memory only (lost on restart)
Problems
- In-memory only — restart the DRb process = lose all counts until CouchDB reload
- Single-process — DRb runs one Ruby process, single point of failure
- Separate process — another thing to monitor, deploy, and restart
- Race conditions — between Puma workers, increment/decrement is not atomic across the DRb boundary
- Custom code —
InMemoryQCounteris 100 lines of hand-rolled counter logic
Target state
Supplier::Counters
→ Mozo::Counter.incr/decr/get/set
→ Mozo::Counter.connection (Mozo::Counter::Redis.new)
→ Redis (localhost:6379)
→ persistent, atomic, multi-process safe
How to switch
In config/initializers/mozo_settings.rb, change:
# Mozo::Counter.connection = Mozo::DrbCounter.object # old
Mozo::Counter.connection = Mozo::Counter::Redis.new # new
That's it. All existing Mozo::Counter.get/set/incr/decr calls work unchanged.
What Redis provides
- Atomic INCR/DECR — no race conditions
- Persistence — RDB snapshots + AOF, survives restarts
- Multi-process — all Puma workers share the same Redis
- Already needed — ActionCable uses Redis for pub/sub in production
- Battle-tested — millions of deployments
Migration steps
apt-get install redis-server— already done on vmi3300327gem 'redis', '~> 5.0'— added to Gemfile- Switch
Mozo::Counter.connection— one-line change in mozo_settings.rb - Stop the DRb counter process (
drb_counter/drb_counter.rb)