Thrift Ruby Software Library

License

Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Using Thrift with Ruby

Ruby bindings for the Apache Thrift RPC system. The gem contains the runtime types, transports, protocols, and servers used by generated Ruby code for both clients and services.

Compatibility

  • Ruby MRI >= 2.7 (tested against current supported releases).
  • JRuby works with the pure-Ruby implementation; the native extension is skipped automatically.
  • For the repo-wide transport, protocol, and server support matrix, see Language Feature Matrix. This README focuses on Ruby-specific behavior and migration notes.

Installation

  • Requirements: Ruby >= 2.7.
  • From RubyGems: gem install thrift
  • From source: bundle install, gem build thrift.gemspec, then install the resulting thrift-*.gem. The native accelerator is built when the gem is installed on supported runtimes.

Generating Ruby Code

The Ruby library does not include the Thrift compiler. Use a compiler built from the root of this repository to generate Ruby bindings:

thrift --gen rb path/to/service.thrift
# with namespaced modules
thrift --gen rb:namespaced --recurse path/to/service.thrift

Generated files are typically written to gen-rb/ and can be required directly from your application.

Basic Client Usage

$:.push File.expand_path('gen-rb', __dir__)
require 'thrift'
require 'calculator'

socket     = Thrift::Socket.new('localhost', 9090)
transport  = Thrift::BufferedTransport.new(socket)
protocol   = Thrift::BinaryProtocol.new(transport)
client     = Calculator::Client.new(protocol)

transport.open
puts client.add(1, 1)
transport.close

Basic Server Usage

$:.push File.expand_path('gen-rb', __dir__)
require 'thrift'
require 'calculator'

class CalculatorHandler
  def add(a, b)
    a + b
  end
end

handler            = CalculatorHandler.new
processor          = Calculator::Processor.new(handler)
server_transport   = Thrift::ServerSocket.new(9090)
transport_factory  = Thrift::BufferedTransportFactory.new
protocol_factory   = Thrift::BinaryProtocolFactory.new

server = Thrift::ThreadedServer.new(processor, server_transport,
                                    transport_factory, protocol_factory)
server.serve

Development and Tests

  • bundle exec rake spec runs the Ruby specs. It expects a built Thrift compiler at ../../compiler/cpp/thrift.
  • bundle exec rake test runs the cross-language test suite; it must be executed from a full Thrift checkout.
  • bundle exec rake build_ext (implicit in the tasks above) compiles the optional native extension that accelerates protocols and buffers.

More Ruby Code

  • Tutorial client and server: tutorial/rb/RubyClient.rb and tutorial/rb/RubyServer.rb
  • Runtime benchmarks: lib/rb/benchmark
  • Protocol benchmark: test/rb/benchmarks/protocol_benchmark.rb
  • Library specs: lib/rb/spec
  • Fuzzing harnesses and notes: lib/rb/test/fuzz
  • Cross-language and integration tests: test/rb

Breaking Changes

0.23.0

The documented source-build flow now effectively requires Ruby 2.7+. The committed development bundle no longer resolves on Ruby 2.6 (json-2.18.1 requires ruby version >= 2.7), so building and testing this library from source should be treated as 2.7+.

Generated structs and unions now consistently raise Thrift::ProtocolException::INVALID_DATA for invalid payloads such as unset required fields, invalid enum values, or invalid union state. If your application or tests matched older exception types or messages, update them.

Regenerated Ruby clients now validate replies more strictly. Mismatched reply message types, method names, or sequence IDs raise Thrift::ApplicationException::INVALID_MESSAGE_TYPE, Thrift::ApplicationException::WRONG_METHOD_NAME, or Thrift::ApplicationException::BAD_SEQUENCE_ID. If you relied on older, looser reply handling in servers, proxies, or tests, regenerate and update those call paths together.

Generated Ruby clients have never been safe to share across concurrent threads. A client tracks pending sequence IDs on a single reply stream, so use one client/transport pair per thread or serialize access yourself.

Treat Thrift::ApplicationException::BAD_SEQUENCE_ID as a correctness bug that needs immediate attention. It means the client read a reply whose sequence ID did not match the next pending request, so the connection may already be out of sync and you may be reading a reply intended for a different call. The most common cause is sharing one client across threads, but a buggy proxy or server can also cause it.

0.13.0

Ruby development and CI moved to Ruby 2.4+, but the runtime still claimed support for older interpreters. Treat Ruby < 2.4 on the 0.13.x line as best-effort, not guaranteed.

  • Historical note for very old releases: the Ruby runtime was rearranged to use more Ruby-like names, and generated files switched to underscored filenames. If you are upgrading very old code, regenerate your Ruby bindings and update any old T* constants or legacy require paths such as TBinaryProtocol -> Thrift::BinaryProtocol.

  • rb:namespaced changes the generated file layout. Flat output from thrift --gen rb and namespaced output from thrift --gen rb:namespaced use different require paths, so switch them atomically with regenerated code.

    # --gen rb
    require 'calculator'
    
    # --gen rb:namespaced
    require 'my_namespace/calculator'
    

Migration Notes

  • If you upgrade across the stricter reply-validation changes, regenerate all Ruby stubs and deploy them with the matching Ruby runtime. Do not mix old generated code, new generated code, and new runtime code on the same client path without testing that combination.
  • If you receive Thrift::ApplicationException::BAD_SEQUENCE_ID, treat the connection as out of sync. Close it, create a new client/transport pair, and investigate the root cause before retrying.
  • Do not share one generated Ruby client across concurrent threads. Use one client/transport pair per thread, or serialize access to a shared client.
  • If you switch between thrift --gen rb and thrift --gen rb:namespaced, regenerate all Ruby output and update require paths in the same change.

Runtime Notes

  • Loading the thrift_native extension changes which implementation you are running. It replaces Thrift::Struct, Thrift::Union, and Thrift::CompactProtocol methods with C implementations in place. Thrift::BinaryProtocol remains available in pure Ruby, and the C-backed binary protocol is opt-in through Thrift::BinaryProtocolAcceleratedFactory or Thrift::BinaryProtocolAccelerated when that class is available.
  • The native extension is optional. If it cannot be built or loaded, Thrift falls back to the pure-Ruby implementation. This mainly changes performance and implementation details.
  • JRuby skips the native extension automatically and uses the pure-Ruby path.
  • Do not share one client instance across concurrent threads. A client tracks request and reply state on a single transport stream.
  • Thrift::NonblockingServer expects framed input. Use Thrift::FramedTransport with it on the wire.
  • Client and server must agree on transport and protocol choices. If you switch to SSL, HTTP, header transport, compact protocol, or namespaced generated code, update both ends together.
  • HTTPS client transport verifies peers by default, and Thrift::SSLSocket performs a hostname check against the host you pass in.