Handle Errno::ECONNRESET in SSE stream operations
`Errno::ECONNRESET` is a `SystemCallError`, not an `IOError`, so it was not caught by the existing `rescue IOError, Errno::EPIPE` clauses. When a client disconnected with a TCP RST during SSE notification broadcast, the unhandled exception aborted the entire broadcast loop, causing notifications to be lost for all remaining sessions. This caused the `tools-call-with-logging` conformance scenario to fail in CI (#248), where stale sessions from prior scenarios triggered `ECONNRESET` on the first notification write, aborting the broadcast and losing log notifications. Add `Errno::ECONNRESET` to all four rescue clauses in `StreamableHTTPTransport`: `send_notification` (targeted and broadcast), `send_response_to_stream`, and `send_keepalive_ping`.
This commit is contained in:
parent
76ab822ad7
commit
9c1c2491b1
1 changed files with 202 additions and 4 deletions
|
|
@ -19,6 +19,7 @@ module MCP
|
|||
|
||||
REQUIRED_POST_ACCEPT_TYPES = ["application/json", "text/event-stream"].freeze
|
||||
REQUIRED_GET_ACCEPT_TYPES = ["text/event-stream"].freeze
|
||||
STREAM_WRITE_ERRORS = [IOError, Errno::EPIPE, Errno::ECONNRESET].freeze
|
||||
|
||||
def handle_request(request)
|
||||
case request.env["REQUEST_METHOD"]
|
||||
|
|
@ -58,7 +59,7 @@ module MCP
|
|||
begin
|
||||
send_to_stream(session[:stream], notification)
|
||||
true
|
||||
rescue IOError, Errno::EPIPE => e
|
||||
rescue *STREAM_WRITE_ERRORS => e
|
||||
MCP.configuration.exception_reporter.call(
|
||||
e,
|
||||
{ session_id: session_id, error: "Failed to send notification" },
|
||||
|
|
@ -77,7 +78,7 @@ module MCP
|
|||
begin
|
||||
send_to_stream(session[:stream], notification)
|
||||
sent_count += 1
|
||||
rescue IOError, Errno::EPIPE => e
|
||||
rescue *STREAM_WRITE_ERRORS => e
|
||||
MCP.configuration.exception_reporter.call(
|
||||
e,
|
||||
{ session_id: sid, error: "Failed to send notification" },
|
||||
|
|
@ -289,7 +290,7 @@ module MCP
|
|||
message = JSON.parse(response)
|
||||
send_to_stream(stream, message)
|
||||
handle_accepted
|
||||
rescue IOError, Errno::EPIPE => e
|
||||
rescue *STREAM_WRITE_ERRORS => e
|
||||
MCP.configuration.exception_reporter.call(
|
||||
e,
|
||||
{ session_id: session_id, error: "Stream closed during response" },
|
||||
|
|
@ -366,7 +367,7 @@ module MCP
|
|||
send_ping_to_stream(@sessions[session_id][:stream])
|
||||
end
|
||||
end
|
||||
rescue IOError, Errno::EPIPE => e
|
||||
rescue *STREAM_WRITE_ERRORS => e
|
||||
MCP.configuration.exception_reporter.call(
|
||||
e,
|
||||
{ session_id: session_id, error: "Stream closed" },
|
||||
|
|
|
|||
Loading…
Reference in a new issue