Abhi Yerra

Rants of lunatic

Being Thrifty with Thrift

leave a comment »

I’ve been using Thrift a RPC  framework from Facebook. It allows you to define a service outline and generate a template in various languages which you can then use to create the service. What this means is you can say use Haskell for you server and hook it up with a Ruby client or vice versa.

I installed thrift on my Mac from the subversion repository. Here are the commands to install the pre-reqs and thrift itself assuming you have MacPorts.

sudo port install boost libevent
svn co https://svn.apache.org/repos/asf/incubator/thrift/trunk thrift
cd thrift
./bootstrap
./configure --prefix=/opt/local/
make
make install

Now that’s settled here is an example of a thrift definition file. Named myauth.thrift


namespace rb MyAuth
namespace py myauth

struct User {
  1: string username,
  2: string password
}

enum LoginStatus {
  SUCCESS,
  FAIL
}

service Authentication {
  string say_hello(),
  LoginStatus login(1:User cred)
}

As you can see this has several components to it. The first the namespace definitions. These are the modules/packages/namespaces which this service belongs to. You can define one for each of the languages that you are going to code for. The second is the User struct which holds the data that we will be working with in the service, third the enums and finally the service definition. The service definition has two methods: say_hello which returns a string and login which returns a LoginStatus taking in a User struct as an argument.

This only uses a subset of the definition syntax to show a small example of what you can do with the service. To see a more thorough example of the definition file go to the Thrift Wiki.

Once you have written the definition compile the file (here I’m going to use Ruby and Python):

thrift --gen rb --gen py myauth.thrift

Now write the server code (in ruby):


require 'thrift'
$:.push('gen-rb')

require 'Authentication'
require 'myauth_constants'

class AuthenticationHandler
  def say_hello
    puts "thrift client connected"
    "hello thrift client"
  end

  def login cred
    if cred.username == 'hello' && cred.password == 'world'
      puts "logged in"
      return MyAuth::LoginStatus::SUCCESS
    end

    puts "great pie of fail"
    MyAuth::LoginStatus::FAIL
  end
end

handler = AuthenticationHandler.new
processor = MyAuth::Authentication::Processor.new(handler)
transport = Thrift::ServerSocket.new(9090)
transportFactory = Thrift::BufferedTransportFactory.new()
server = Thrift::SimpleServer.new(processor, transport, transportFactory)

puts "Starting the server..."
server.serve()
puts "done."

Write the client code (in python):


import sys
sys.path.append('gen-py')

from myauth import Authentication
from myauth.constants import *

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

transport = TSocket.TSocket('localhost', 9090)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)

auth = Authentication.Client(protocol)

transport.open()

print auth.say_hello()

user = User()
user.username = 'hello'
user.password = 'world'

print "Login: %s" % auth.login(user)

user2 = User()
user2.username = 'failed'
user2.password = 'world'

print "Login: %s" % auth.login(user2)

What thrift gives you is a transport layer as well as a protocol layer so you don’t have to worry about mucking around with sockets. There are also several protocol layers defined so you could use a JSON protocol for example.

All in all this is a useful technology for using the right tool for the job, i.e the right programming language for the job. By working with different languages thrift gives the programmer the capability of writing different services using the strengths of the appropriate language.

Written by abhiyerra

March 29, 2009 at 2:38 am

Posted in code, technology

Tagged with ,

Leave a Reply