Module: CableRoom::Room::Threading
Instance Method Summary collapse
-
#async(&blk) ⇒ Object
Run the given block off the Room's thread, so slow work doesn't stop the Room from processing anything else.
-
#on_room_thread(&blk) ⇒ Object
Queue the block back onto the Room's own thread, where touching Room state is safe again.
Instance Method Details
#async(&blk) ⇒ Object
Run the given block off the Room's thread, so slow work doesn't stop the Room from processing anything else.
A Room is otherwise single-threaded: messages and timers run one at a time, which is what makes Room state safe to touch without locks. Work posted here deliberately escapes that queue and runs concurrently with the Room, so it must not reference Room state. Capture everything the block needs before posting it:
token = .token
async { expensive_lookup(token) } # good - `token` was captured
async { expensive_lookup() } # BAD - races the Room's thread
In particular message is nil inside the block (it is thread-local to the Room's thread),
and message_origin and reply refer to whatever the Room is handling now rather than
what it was handling when async was called.
self is still the Room, so instance methods resolve normally - which is exactly why the
state rule matters. To act on the result, hand it back to the Room's thread:
token = .token
async do
result = expensive_lookup(token)
on_room_thread { broadcast({ type: 'result', result: result }, client_port: token) }
end
Exceptions are reported through CableRoom.error_handler, the same as any other Room work.
Note that this borrows a thread from the worker pool shared by every Room in the process,
so blocking a Room's thread waiting on async work can starve other Rooms. Prefer handing
results back with on_room_thread over waiting for them.
37 38 39 40 |
# File 'lib/cable_room/room/threading.rb', line 37 def async(&blk) room = self @cable_channel.post_work(async: true) { room.instance_exec(&blk) } end |
#on_room_thread(&blk) ⇒ Object
Queue the block back onto the Room's own thread, where touching Room state is safe again.
43 44 45 46 |
# File 'lib/cable_room/room/threading.rb', line 43 def on_room_thread(&blk) room = self @cable_channel.post_work(async: false, silent: true) { room.instance_exec(&blk) } end |