简体   繁体   中英

Blocking Thrift calls with Twisted

I have a Twisted/Thrift server that uses the TTwisted protocol. I want to keep connections from clients open until a given event happens (I am notified of this event by the Twisted reactor via a callback).

class ServiceHandler(object):
    interface.implements(Service.Iface)

    def listenForEvent(self):
        """
        A method defined in my Thrift interface that should block the Thrift
        response until my event of interest occurs.
        """
        # I need to somehow return immediately to free up the reactor thread,
        # but I don't want the Thrift call to be considered completed. The current
        # request needs to be marked as "waiting" somehow.

    def handleEvent(self):
        """
        A method called when the event of interest occurs. It is a callback method
        registered with the Twisted reactor.
        """
        # Find all the "waiting" requests and notify them that the event occurred.
        # This will cause all of the Thrift requests to complete.

How can I quickly return from a method of my handler object while maintaining the illusion of a blocking Thrift call?


I initialize the Thrift handler from the Twisted startup trigger:

def on_startup():
    handler = ServiceHandler()                      
    processor = Service.Processor(handler)                                   
    server = TTwisted.ThriftServerFactory(processor=processor,                  
        iprot_factory=TBinaryProtocol.TBinaryProtocolFactory())                 
    reactor.listenTCP(9160, server)

My client in PHP connects with:

  $socket = new TSocket('localhost', 9160);
  $transport = new TFramedTransport($socket);
  $protocol = new TBinaryProtocol($transport);
  $client = new ServiceClient($protocol);
  $transport->open();
  $client->listenForEvent();

That last call ( $client->listenForEvent() ) successfully makes it over to the server and runs ServiceHandler.listenForEvent , but even when that server method returns a twisted.internet.defer.Deferred() instance, the client immediately receives an empty array and I get the exception:

exception 'TTransportException' with message 'TSocket: timed out reading 4 bytes from localhost:9160 to local port 38395'

You should be able to return a Deferred from listenForEvent . Later handleEvent should fire that returned Deferred (or those returned Deferreds) to actually generate the response.

The error you're seeing seems to indicate that the transport is not framed (Twisted needs it to be so it can know the length of each message beforehand). Also, Thrift servers support returning deferreds from handlers, so that's even more strange. Have you tried returning defer.succeed("some value") and see if deferreds actually work? You can then move to this to check that it fully works:

    d = defer.Deferred()
    reactor.callLater(0, d.callback, results)
    return d

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM