<div dir="ltr"><div><div><div>Hi all<br><br></div>I'm building a simple TCP load balancer based on a code snippet from Glyph on SO: <a href="http://stackoverflow.com/questions/4096061/general-question-regarding-wether-or-not-use-twisted-in-tcp-proxy-project">http://stackoverflow.com/questions/4096061/general-question-regarding-wether-or-not-use-twisted-in-tcp-proxy-project</a><br>
<br></div>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'.<br>
<br>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?<br>
<br></div>An example is below. The hashed out buildProtocol is a synchronous decision which works. Thanks in advance!<br><br>from twisted.internet.protocol import Factory<br>from twisted.protocols.portforward import ProxyFactory<br>
from twisted.internet import reactor, defer<br>import random<br><br>from twisted.python import log<br>import sys<br>log.startLogging(sys.stderr)<br><br>local_ports = set([1024, 1025])<br><br>def port_routing_decision_sync():<br>
    return random.choice(list(local_ports))<br><br>def port_routing_decision_async():<br>    d = defer.Deferred()<br>    reactor.callLater(1, d.callback, port_routing_decision_sync())<br>    return d<br><br>class Balancer(Factory):<br>
    # def buildProtocol(self, addr):<br>    #     port = port_routing_decision_sync()<br>    #     print "connecting to local port {}".format(port)<br>    #     return ProxyFactory("127.0.0.1", port).buildProtocol(addr)<br>
<br>    @defer.inlineCallbacks<br>    def buildProtocol(self, addr):<br>        port = yield port_routing_decision_async()<br>        print "connecting to local port {}".format(port)<br>        defer.returnValue(ProxyFactory("127.0.0.1", port).buildProtocol(addr))<br>
<br>def main():<br>    factory = Balancer()<br>    reactor.listenTCP(5678, factory)<br>    reactor.run()<br><br>if __name__ == "__main__":<br>    main()<br></div>