Module: Hibiki::Rails::Channel
- Defined in:
- lib/hibiki/rails/channel.rb
Overview
Include into an ActionCable channel to host one connection-scoped signal graph:
class CounterChannel < ApplicationCable::Channel
include Hibiki::Rails::Channel
def build_graph # runs on the graph's own thread,
@count = Hibiki::State.new(0) # inside Hibiki.root
Hibiki::Effect.new { ... broadcast ... }
end
def increment = @count.value += 1 # actions are plain methods
end
Lifecycle: subscribed rejects without a cid param, then builds the
graph via #build_graph inside Hibiki.root on a dedicated GraphActor
thread; every incoming action runs on that same thread inside one
Hibiki.batch (N writes per action still mean one re-run per affected
effect); unsubscribed disposes the root and stops the actor.
A channel that overrides subscribed/unsubscribed itself must call
super.
NOTE: everything this module adds is private (except the #perform_action override, which ActionCable already exposes) — any other public method would be picked up by Channel#action_methods and become client-invocable.
Defined Under Namespace
Modules: ClassMethods
Class Method Summary collapse
Instance Method Summary collapse
-
#perform_action(data) ⇒ Object
ActionCable's single dispatch point for incoming actions.
Class Method Details
.included(base) ⇒ Object
33 34 35 36 |
# File 'lib/hibiki/rails/channel.rb', line 33 def self.included(base) base.extend(ClassMethods) base.include(Broadcasts) end |
Instance Method Details
#perform_action(data) ⇒ Object
ActionCable's single dispatch point for incoming actions. The whole action body is posted to the graph's thread and wrapped in one batch — cable threads never touch the graph. Spike-verified: batch per action is all the coalescing the replace-partial style needs.
rescue_from handlers still run (dispatch_action applies them
inside the job, now on the graph thread); what they don't handle
propagates to the actor's on_error — ::Rails.error by default.
The client stamps a sequence number under the reserved hbk key to
get a post-batch ack back, which is what stops its pending
indicator. It cannot wait for a render instead: the core's equality
gate (hibiki 0.2.0) means an ordinary action — paging to the page
you are already on, a search that doesn't change the query, a
destroy of a row another tab already deleted — legitimately
produces zero bytes, and "clear on the next render" would hang
forever. delete, not []: the key must not reach the action
method's data. No hbk, no ack, so a 0.3.0 page keeps working.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/hibiki/rails/channel.rb', line 76 def perform_action(data) seq = data.delete("hbk") # A nil actor means the subscription was rejected or already torn # down; drop the action rather than blow up the cable thread. posted = @__hibiki_actor&.post do Hibiki.batch { super(data) } ensure # Hibiki.batch flushes in its own ensure, so effects queued # before a raise have run by the time this does — the ack is # genuinely post-batch. GraphActor#work rescues around the whole # job, so without this a raising action would hang the indicator # in exactly the case the user most needs it to stop. transmit({ ack: seq }) if seq end # post yields nil (no actor) or false (queue closed): the block # never ran, so neither did its ensure. `dropped` is also what lets # the client tell "late" from "never" — nothing is coming for this # seq, so it settles immediately rather than waiting out the grace # window. transmit({ ack: seq, dropped: true }) if seq && !posted end |