You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@thrift.apache.org by "Dmytro Shteflyuk (Jira)" <ji...@apache.org> on 2026/07/29 22:14:00 UTC
[jira] [Resolved] (THRIFT-6125) Ruby client leaves transports reusable after uncertain request sends
[ https://issues.apache.org/jira/browse/THRIFT-6125?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Dmytro Shteflyuk resolved THRIFT-6125.
--------------------------------------
Fix Version/s: 0.25.0
Resolution: Fixed
> Ruby client leaves transports reusable after uncertain request sends
> --------------------------------------------------------------------
>
> Key: THRIFT-6125
> URL: https://issues.apache.org/jira/browse/THRIFT-6125
> Project: Thrift
> Issue Type: Bug
> Components: Ruby - Library
> Reporter: Dmytro Shteflyuk
> Assignee: Dmytro Shteflyuk
> Priority: Major
> Fix For: 0.25.0
>
> Time Spent: 20m
> Remaining Estimate: 0h
>
> h3. Problem
> The Ruby client closes its output transport when argument serialization fails, but not when writing the message envelope, finishing the message, or flushing the transport fails.
> Once message writing has begun, an exception does not reliably indicate whether zero, some, or all request bytes reached the underlying connection. Leaving that connection open allows a later call to reuse transport state whose wire outcome is unknown. A buffered transport may still contain request data, while an unbuffered transport may already have emitted part or all of the request.
> Argument construction is different: when creating or assigning the generated arguments fails before message writing starts, no bytes have been published and the connection remains safe to reuse.
> h3. Client impact
> After a write or flush error, an application may catch the exception and make another call with the same generated client. Because the Ruby client currently leaves the transport open, that later request can follow incomplete or retained data from the failed request. This can desynchronize the client and server or make it unclear which request a subsequent response belongs to.
> The behavior affects both ordinary calls and oneway calls. For ordinary calls, a failed send must also not add a sequence ID to the pending-reply queue.
> h3. Reproduction
> The following example uses a transport that accepts request bytes but fails during flush:
> {code:ruby}
> require "thrift"
> class FailingFlushTransport < Thrift::BaseTransport
> attr_reader :closed
> def write(_data)
> end
> def flush
> raise Thrift::TransportException.new(
> Thrift::TransportException::UNKNOWN,
> "flush failed"
> )
> end
> def close
> @closed = true
> end
> end
> class EmptyArgs
> def write(_protocol)
> end
> end
> class ExampleClient
> include Thrift::Client
> end
> transport = FailingFlushTransport.new
> protocol = Thrift::BinaryProtocol.new(transport)
> client = ExampleClient.new(protocol)
> begin
> client.send_message("example", EmptyArgs)
> rescue Thrift::TransportException => error
> puts "#{error.message}; closed=#{transport.closed.inspect}"
> end
> {code}
> The current implementation prints:
> {noformat}
> flush failed; closed=nil
> {noformat}
> The transport therefore remains available for another request even though delivery of the failed request is uncertain.
> h3. Expected behavior
> The client should construct and assign arguments before beginning message output. Failures at that stage should leave the transport open and should not consume a sequence ID.
> After message output begins, an exception from the envelope, argument serialization, message end, or flush should close the output transport and re-raise the original exception. A failure while closing must not replace the original send error. Ordinary calls should enter the pending-reply queue only after a successful flush, and oneway calls should follow the same transport-closing rule.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)