Class: MCP::Server::PendingResponse
- Inherits:
-
Object
- Object
- MCP::Server::PendingResponse
- Defined in:
- lib/mcp/server/pending_response.rb
Overview
A one-shot, timeout-aware handoff between the thread awaiting a server-to-client response and whichever thread resolves it (the client's response, a cancellation, or session teardown).
Queue#pop only accepts a timeout: on Ruby 3.2 and later, and this gem supports 2.7,
so the wait is expressed with a ConditionVariable. The push/pop names mirror the Queue
this replaces, keeping the resolving call sites unchanged.
First writer wins: a second push is ignored, so a cancellation that races a real response
cannot overwrite it. pop returns the pushed value, or the on_timeout result when
the deadline passes with nothing pushed.
Instance Method Summary collapse
-
#initialize ⇒ PendingResponse
constructor
A new instance of PendingResponse.
-
#pop(timeout:) ⇒ Object
Blocks until a value is pushed or
timeoutseconds elapse, and yields to the caller on expiry so it can decide what a timeout means. -
#push(value) ⇒ Object
Resolves the wait.
Constructor Details
#initialize ⇒ PendingResponse
Returns a new instance of PendingResponse.
16 17 18 19 20 21 |
# File 'lib/mcp/server/pending_response.rb', line 16 def initialize @mutex = Mutex.new @condition = ConditionVariable.new @delivered = false @value = nil end |
Instance Method Details
#pop(timeout:) ⇒ Object
Blocks until a value is pushed or timeout seconds elapse, and yields to the caller
on expiry so it can decide what a timeout means. ConditionVariable#wait can return spuriously,
so the deadline is re-checked against the monotonic clock.
The expiry block runs after the lock is released: it typically cancels the request,
which resolves this same object, and Ruby's Mutex is not reentrant.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/mcp/server/pending_response.rb', line 40 def pop(timeout:) deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout expired = false value = @mutex.synchronize do until @delivered remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC) if remaining <= 0 expired = true break end @condition.wait(@mutex, remaining) end @value end expired ? yield : value end |
#push(value) ⇒ Object
Resolves the wait. Ignored when a value was already delivered.
24 25 26 27 28 29 30 31 32 |
# File 'lib/mcp/server/pending_response.rb', line 24 def push(value) @mutex.synchronize do next if @delivered @delivered = true @value = value @condition.broadcast end end |