cable_room 0.6.2.beta3 → 0.7.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +122 -0
  3. data/README.md +1190 -0
  4. data/cable_room.gemspec +5 -2
  5. data/exe/cable_room +8 -0
  6. data/lib/cable_room/broadcaster.rb +116 -0
  7. data/lib/cable_room/bus.rb +372 -0
  8. data/lib/cable_room/cli.rb +237 -0
  9. data/lib/cable_room/config.rb +112 -0
  10. data/lib/cable_room/host/bus_inbound.rb +36 -0
  11. data/lib/cable_room/host/runner.rb +571 -0
  12. data/lib/cable_room/host/supervisor.rb +275 -0
  13. data/lib/cable_room/host/worker_pool.rb +37 -0
  14. data/lib/cable_room/host.rb +477 -0
  15. data/lib/cable_room/membership_store.rb +105 -0
  16. data/lib/cable_room/migration.rb +586 -0
  17. data/lib/cable_room/periodic_timer.rb +18 -0
  18. data/lib/cable_room/placement.rb +258 -0
  19. data/lib/cable_room/ports.rb +19 -11
  20. data/lib/cable_room/railtie.rb +3 -12
  21. data/lib/cable_room/room/base.rb +45 -39
  22. data/lib/cable_room/room/host_adapter.rb +52 -0
  23. data/lib/cable_room/room/lifecycle.rb +26 -9
  24. data/lib/cable_room/room/port_management.rb +58 -4
  25. data/lib/cable_room/room/reaping.rb +34 -1
  26. data/lib/cable_room/room/snapshotting.rb +78 -0
  27. data/lib/cable_room/room/threading.rb +2 -2
  28. data/lib/cable_room/room/user_management.rb +27 -0
  29. data/lib/cable_room/room.rb +5 -2
  30. data/lib/cable_room/room_member.rb +258 -13
  31. data/lib/cable_room/room_proxy_channel.rb +13 -2
  32. data/lib/cable_room/snapshot.rb +136 -0
  33. data/lib/cable_room/version.rb +1 -1
  34. data/lib/cable_room.rb +57 -2
  35. metadata +25 -9
  36. data/lib/cable_room/channel_base.rb +0 -247
  37. data/lib/cable_room/channel_tracker.rb +0 -130
  38. data/lib/cable_room/room/channel_adapter.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5984faba13ce4bcbfc7cdcde1eee9a268ca8ea59227efd2cbe41532d67892782
4
- data.tar.gz: 651af8589e9709f27e3cfee877fe2359c931919d3c853c74d097147b245d37f1
3
+ metadata.gz: 890aa545d8211663c2270322da9440b0dbd685e7cdcfa9858df04390d06e7533
4
+ data.tar.gz: 074e6c49a9886c90483500bdb61cdf40fa4d3c9e83ddc583415cc9ac051e90f6
5
5
  SHA512:
6
- metadata.gz: 9f85aa97a935a9cc11049b5ce408f06cacca2ff1309800e13b4b4a9b750c68612d3991410f081e5c99a43b0282bbc42071418d856d728c3bda03381ec48ba85c
7
- data.tar.gz: f94b0ac04d23f0bbb411b7f1e9432b09f778756046bcc6b6f3ed02557ca1020f97dc62e6c238b4259d581a92647cba726251037d2b59fd2c93c884c139a59ed4
6
+ metadata.gz: 3304bd77c3d455a2b867d83d82d4985ff7e1a3ec10bd80ec6a097f50be040fadbbaac501d7f26234384ba50dbe9f09864c92e1114d8cecff75d308ae2a770261
7
+ data.tar.gz: 408c73ab717cd8aaa5a7fbc8ce6b5d209ee2169fe50a731ac8b6d7b2b417b61e64c5a9ceac55155e07e677f6b3a952bb56edd4043a16b624bb264cd6ca1fb21d
data/CHANGELOG.md ADDED
@@ -0,0 +1,122 @@
1
+ # Changelog.
2
+
3
+ ## 1.0.0
4
+
5
+ Rooms can now run in their own process pool, and browsers can be served by anycable-go. Every
6
+ Room definition from 0.6 works unchanged. The channel and deployment contracts do change; the
7
+ README's "Upgrading from 0.6 to 1.0" section is the checklist.
8
+
9
+ ### Breaking.
10
+
11
+ - **Clients must send `hello`.** A membership no longer announces itself to the Room when the
12
+ channel subscribes. The browser performs `hello` once ActionCable confirms the subscription
13
+ (`connected()` in the JS client), and only then does `port_connected` go out. There is no
14
+ fallback: a client that never says `hello` receives broadcasts on the shared stream, but the
15
+ Room never sees it and everything it sends is dropped. Browser tabs open across the deploy
16
+ speak the old handshake and stay deaf until reloaded.
17
+ - **`ChannelBase`, `ChannelTracker`, and `DummyConnection` are gone.** Rooms no longer run inside
18
+ a synthetic ActionCable channel. `CableRoom::Host` (one per process) and `Host::Runner` (one
19
+ per Room) own the work queue, worker pool, scheduler, Redlock renewal, watchdog, and shutdown.
20
+ Internal names apps may have reached for moved with them:
21
+ - inside a Room, `@cable_channel` is now `@runner` (a `Host::Runner`);
22
+ - the `CableRoom.error_handler` context key `channel:` is now `runner:` (with `room:`,
23
+ `room_class:`, and `room_key:` alongside it);
24
+ - `Room#params` is gone (it delegated to the synthetic channel, which had none);
25
+ - `ChannelTracker::BEAT_INTERVAL` is `Host::BEAT_INTERVAL`;
26
+ - `Room::ChannelAdapter` is `Room::HostAdapter`, and the `MyRoom::Channel` constant no longer
27
+ exists;
28
+ - `CableRoom::Room.locally_open_rooms` and `MyRoom.locally_running_instances` read from the
29
+ Host and return `[]` in a process that hosts no Rooms.
30
+ - **Provisioning happens over the bus.** `join_room(..., create: true)` never starts a Room in
31
+ the member's process. It publishes a `provision` request (at join and on every ping until the
32
+ Room acknowledges the port), and one of the hosts starts the Room after a load-weighted
33
+ delay. `Room::Base.ensure` still starts a Room directly, but only in a process that hosts
34
+ Rooms: in a `room_host = :remote` web process it raises `CableRoom::Host::NotHosting`.
35
+ - **Member→room traffic rides cable_room's own Redis.** Everything a member sends (`to_room`,
36
+ `port_connected`, `port_ping`, `port_disconnected`, custom ports) and `Room::Base.send_message`
37
+ publish on `CableRoom::Bus`, over the `CABLEROOM_*` connection. The Room side no longer
38
+ touches ActionCable pubsub for inbound. That connection must be reachable from every web
39
+ process and every rooms host.
40
+ - **`redis` is a runtime dependency** (`>= 5.0`). It was a development dependency; rediconn
41
+ needed it all along, and the bus uses it directly.
42
+ - **`PortManagement::PORT_TIMEOUT` is 45 seconds**, up from 30. A member that stops pinging
43
+ keeps its port 15 seconds longer.
44
+ - **`room_closed` always carries a reason.** In 0.6 a close the host decided (process exit,
45
+ watchdog timeout, lost lock) sent `reason: nil`; only `shutdown!` from inside the Room set one.
46
+ Now the runner sets it too: `"Server shutting down"`, `"Watchdog timeout"`, the signal name on
47
+ a `cable_room server` drain, and the failure on a migration that closed instead of moving.
48
+ - **Instrumentation payloads.** `error.cable_room` and the error handler get the new context
49
+ keys above. Every 0.6 event still fires with the same name.
50
+
51
+ ### Added.
52
+
53
+ - `CableRoom.configure` / `CableRoom.config` (`CableRoom::Config`) with five knobs:
54
+ `room_host` (`:inline` | `:remote`), `broadcaster` (`:action_cable` | `:anycable`),
55
+ `provision_delay_ms` (20), `drain_timeout` (10 minutes), and `handoff_timeout` (10 seconds).
56
+ `CABLE_ROOM_HOST` and `CABLE_ROOM_BROADCASTER` override the first two, even when the block sets
57
+ them. Unknown values raise at boot and name the valid options. Defaults reproduce 0.6.
58
+ - `CableRoom::Broadcaster`: room→member traffic goes through `ActionCableBroadcaster`
59
+ (`ActionCable.server.broadcast`, the default) or `AnyCableBroadcaster` (`AnyCable.broadcast`).
60
+ Stream names are identical in both. `anycable-rails` is optional; selecting `:anycable`
61
+ without it raises `Broadcaster::MissingDependency` naming the gem.
62
+ - `CableRoom::Bus`: Redis pub/sub and the handoff storage on the `CABLEROOM_*` connection.
63
+ Channel names: `cr:{RoomClass:key}:in` (and `:in:{port}` for custom ports), `cr:provision`,
64
+ `cr:{RoomClass:key}:handoff`, `cr:{RoomClass:key}:snapshot`, `cr:{RoomClass:key}:adopted`.
65
+ `Room::Base.inbound_channel(key, port)` names a Room's inbound channel.
66
+ - `CableRoom::Host`: `Host.current` (nil when the process hosts nothing), `Host.instance`,
67
+ `Host.start!`, `Host#open_ports` (the load gauge to scale on), `Host#open_rooms_count`,
68
+ `Host#drain!`, `Host.after_drain`, `Host::NotHosting`.
69
+ - `cable_room server` (`exe/cable_room`, `CableRoom::CLI`): boots the Rails app in the current
70
+ directory (or `--require PATH`), refuses to run unless `room_host` is `:remote`, hosts Rooms
71
+ until SIGTERM or SIGINT, and migrates open Rooms to peers on the way out. `--workers N`
72
+ (default: core count) preloads the app and forks N single-GVL workers through
73
+ `Host::Supervisor`, which replaces a worker that dies (with a growing delay for one that dies
74
+ at boot), relays SIGTERM and SIGINT, and waits for every worker. `--version` prints the
75
+ version. `CableRoom.after_fork!` resets the bus, lock manager, Redis pool, and Host in a
76
+ forked child.
77
+ - Load-weighted provisioning (`CableRoom::Placement`): every host hears each `provision`
78
+ request, waits `provision_delay_ms × (open_rooms + jitter)`, then races for the Redlock.
79
+ Exactly one wins. A draining host never claims.
80
+ - Snapshot and restore: optional `snapshot_state` / `restore_state` hooks on a Room,
81
+ `restored?`, `CableRoom::Snapshot` (version 1, gem-owned ports, users, reaper deadlines, and
82
+ `app_state`), `Snapshot::NotSerializable` raised at snapshot time for non-JSON state, and
83
+ `Host#restore_room`. A restored Room runs `restore_state` instead of `startup` when it defines
84
+ it, and never broadcasts `room_opened`.
85
+ - Live migration on planned shutdown (`CableRoom::Migration`): freeze → snapshot → offer (Redis,
86
+ 60 second TTL) → peer adopts → relay and replay with per-stream markers → let go. Members keep
87
+ their streams and lose nothing. A Room nobody adopts within `handoff_timeout` closes with
88
+ `room_closed`; `drain_timeout` forces whatever is still waiting through. New lifecycle states
89
+ `:freezing` and `:frozen`.
90
+ - Channel actions `hello` and `ping` on every `RoomMember` channel (and so on
91
+ `RoomProxyChannel`), plus the server-side `hello_room_memberships`, `RoomMembership#hello!`,
92
+ `#hello_received?`, `#accepts_input?`, and the protected `room_memberships` reader.
93
+ - AnyCable channel state: `CableRoom::MembershipStore` keeps each membership's identity in
94
+ anycable-rails' `state_attr_accessor`, so `hello`, `receive`, `ping`, and `unsubscribed` work
95
+ across anycable-rails' per-call channel instances. Under plain ActionCable nothing changes.
96
+ - New `ActiveSupport::Notifications` events: `hello_received.cable_room`,
97
+ `provision_requested.cable_room`, `provision_claimed.cable_room`, `room_snapshotted.cable_room`,
98
+ `room_restored.cable_room`, `host_draining.cable_room`, and `room_migrated.cable_room`.
99
+ - CI: an `e2e-anycable` job runs `spec/e2e` against a real `anycable/anycable-go:1.6` under both
100
+ Appraisals. Locally it runs only with `CABLE_ROOM_E2E=1`.
101
+ - `CHANGELOG.md` and `exe/` ship in the gem.
102
+
103
+ ### Changed.
104
+
105
+ - `Room::Base.room_port_key` builds the stream name itself (`"RoomClass:key:port"`, records by
106
+ GlobalID). The format is the same one ActionCable produced in 0.6.
107
+ - The ActionCable `restart` hook (development code reload) stops Rooms through the Host.
108
+ - `RoomMembership#stream_port` takes `auto_close:`; the room-side `stream_port` takes `on_live:`.
109
+ - The `Railtie` no longer declares empty `rake_tasks`, `console`, and `runner` blocks.
110
+ - The README describes the 1.0 architecture: configuration, deployment modes, `cable_room
111
+ server`, provisioning, the hello handshake, AnyCable's browser contract, migration, every
112
+ instrumentation event, and the 0.6 → 1.0 upgrade guide.
113
+
114
+ ### Fixed.
115
+
116
+ - The gemspec declares `redis`, which rediconn loads but never listed. An app that didn't have
117
+ `redis` in its own Gemfile could fail to boot with 0.6.
118
+
119
+ ## 0.6.2.beta1
120
+
121
+ The last release before distributed rooms. Rooms ran inside a synthetic ActionCable channel in
122
+ every process that joined them.