Finagled Client and Multiplexed C# Thrift Server Bug

This is an obscure issue, with an easy workaround, but no obvious solution.

You chose the Finagle RPC stack because you have old and dusty C# applications mixed in with your Scala. It’s only inevitable that one day you will connect a Finagle client to your C# server, and it won’t work.

If you:

Yes, your Scala-to-Scala, C#-to-C#, and C#-to-Scala work just fine.

Looking over the com.twitter.finagle.thrift.ThriftClientFramedCodec you spot the magic invocation of ThriftTracing.CanTraceMethodName, a fire-and-forget call to a mysterious __can__finagle__trace__v3__ method.

The unexpecting multiplexed non-finagle service throws an exception upon receiving a call which it cannot route, as it doesn’t conform to the Service.Method format.

Tracing is a great feature, and it makes sense Finagle does what it does (it uses this method upgrade the wire protocol to support more advanced features). A simple workaround is to disable this feature, inherit the codecs: in your ClientBuilder() constructor substitute these in for the call to ThriftClientFramedCodec().

import com.twitter.finagle.{ CodecFactory, ClientCodecConfig, ServiceFactory }
import org.apache.thrift.protocol.{ TProtocolFactory, TBinaryProtocol }
class ThriftClientFramedCodecFactoryWithoutFinagle(
 _protocolFactory: TProtocolFactory = new TBinaryProtocol.Factory())
 extends CodecFactory[ThriftClientRequest, Array[Byte]]#Client {

 def apply(config: ClientCodecConfig) = new {} 
  with ThriftClientFramedCodec(_protocolFactory, config, None, false) {

  override def prepareConnFactory(
    underlying: ServiceFactory[ThriftClientRequest, Array[Byte]]) = underlying
 }
}
class ThriftClientBufferedCodecFactoryWithoutFinagle(
 _protocolFactory: TProtocolFactory = new TBinaryProtocol.Factory())
 extends CodecFactory[ThriftClientRequest, Array[Byte]]#Client {

 def apply(config: ClientCodecConfig) = new {} 
  with ThriftClientBufferedCodec(_protocolFactory, config) {

  override def prepareConnFactory(
    underlying: ServiceFactory[ThriftClientRequest, Array[Byte]]) = underlying
 }
}

In the builder, we change:

ClientBuilder().codec(ThriftClientFramedCodec()).Build()

to

ClientBuilder().codec(new ThriftClientFramedCodecFactoryWithoutFinagle()).Build()

After 10 months, the 0.9.1 release of libthrift is out, now Finagle can officially support multiplexing!

Leave a Reply

Your email address will not be published. Required fields are marked *

Help stop spam, fill out this captch: * Time limit is exhausted. Please reload CAPTCHA.