[Twisted-Python] Returning a deferred from buildProtocol t.i.p.Factory

Tom van Neerijnen twisted at tomvn.com
Sat Nov 16 07:09:48 MST 2013


Hi all

I'm building a simple TCP load balancer based on a code snippet from Glyph
on SO:
http://stackoverflow.com/questions/4096061/general-question-regarding-wether-or-not-use-twisted-in-tcp-proxy-project

It's served me well but I can't work out how to convert Glyphs round robin
retrieval of the server endpoint into an async balancing decision in the
buildProtocol method of the Factory. If I return a deferred here it fails
with an AttributeError: Deferred instance has no attribute 'makeConnection'.

Currently I'm working around this by running a separate management loop
that periodically updates a dictionary with all the data necessary to make
my routing decision so that I can do it without a deferred. This worries me
because I may be making my decision on slightly stale data and I'd really
like this to be a real time decision as the connection comes in. Does
anyone have a clever way of doing this?

An example is below. The hashed out buildProtocol is a synchronous decision
which works. Thanks in advance!

from twisted.internet.protocol import Factory
from twisted.protocols.portforward import ProxyFactory
from twisted.internet import reactor, defer
import random

from twisted.python import log
import sys
log.startLogging(sys.stderr)

local_ports = set([1024, 1025])

def port_routing_decision_sync():
    return random.choice(list(local_ports))

def port_routing_decision_async():
    d = defer.Deferred()
    reactor.callLater(1, d.callback, port_routing_decision_sync())
    return d

class Balancer(Factory):
    # def buildProtocol(self, addr):
    #     port = port_routing_decision_sync()
    #     print "connecting to local port {}".format(port)
    #     return ProxyFactory("127.0.0.1", port).buildProtocol(addr)

    @defer.inlineCallbacks
    def buildProtocol(self, addr):
        port = yield port_routing_decision_async()
        print "connecting to local port {}".format(port)
        defer.returnValue(ProxyFactory("127.0.0.1",
port).buildProtocol(addr))

def main():
    factory = Balancer()
    reactor.listenTCP(5678, factory)
    reactor.run()

if __name__ == "__main__":
    main()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://twistedmatrix.com/pipermail/twisted-python/attachments/20131116/f2c9eadb/attachment.html>


More information about the Twisted-Python mailing list