tags:

views:

21

answers:

1

I have the following:

  1. My webserver running on twisted
  2. My comet server, aka orbited

Note that 1 and 2 are different processes.

Basically, I want 1 and 2 to share the same port. Request that are http://mysite.com/a/b/c should go to the webserver and anything starting with http://mysite.com/orbited/ should go to the orbited server, i.e. (http://mysite.com/orbited/a/b/c => do a request to http://mysite.com:12345/a/b/c and return that).

This is what I have right now:

# Reverse Proxy
class OrbitedResource(Resource):
    isLeaf = True

    def __init__(self, orbited_url='http://127.0.0.1:12345'):
        self.orbited = orbited_url
        Resource.__init__(self)

    def render_GET(self, request):

        def callback(html):
            request.write(html)
            request.finish()

        def errback(failure, *args):
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            request.write(failure.getErrorMessage())
            request.finish()

        request.setHeader('Connection', 'close')

        # TODO find cleaner way to do this:
        # Currently request.uri is "/orbited/....", you must trim it
        target_uri = request.uri.replace('/orbited', '') 
        final_uri = self.orbited + target_uri
        print "final_uri is", final_uri

        deferred = getPage(final_uri)
        deferred.addCallbacks(callback, errback)
        return server.NOT_DONE_YET


class SimpleRoutingResource(Resource):
    isLeaf = False

    def __init__(self, wsgiApp):
        Resource.__init__(self)
        self.WSGIApp = wsgiApp
        self.orbitedResource = OrbitedResource()

    def getChild(self, name, request):
        if name == "orbited":
            request.prepath.pop()
            print "Simple request.path is", request.path
            return self.orbitedResource
        else: 
            request.prepath.pop()
            request.postpath.insert(0,name)
            return self.WSGIApp

# Attaching proxy + django 
log_dir = './.log'
if not os.path.exists(log_dir):
    os.makedirs(log_dir)
reactor.listenTCP(DJANGO_PORT, server.Site(SimpleRoutingResource(WSGIRoot), 
        logPath=os.path.join(log_dir, '.django.log')))

Currently this works . However, I see that there's a class called ReverseProxyProtocol, and I have been doing tried it with the following modification:

class SimpleRoutingResource(Resource):
    isLeaf = False

    def __init__(self, wsgiApp):
        Resource.__init__(self)
        self.WSGIApp = wsgiApp

    def getChild(self, name, request):
        if name == "orbited":
            request.prepath.pop()
            print "Simple request.path is", request.path, name
            return ReverseProxyResource( 'http://localhost', 12345, name )
        else: 
            request.prepath.pop()
            request.postpath.insert(0,name)
            return self.WSGIApp

This is NOT Working. I have inserted a lot of prints into the twisted's reverseProxyResource class, and I discovered the following:

  1. Given http://mysite.com/orbited/a/b/c
  2. OrbitedResource will keep calling ReverseProxyResource with getChild until c
  3. by the time you get to c, the url is messed up and the client class calling the orbited server will be wrong
  4. I tried setting isLeaf = True in the ReverseProxyResource, but to no avail.

Anybody can point me a more effecient way to write the getPage? Do I really need to use ReverseProxyResource if it's such a black box in nature?

A: 

The cleanest way is to put something like nginx in front of both servers.

Marcelo Cantos
I don't think so. Since I am using twisted, it would be much more efficient to have 1 process do all the work. Putting a completely different thing on top would really help much.
disappearedng
@user140330: An extra hop inside the same machine is going to make practically no difference, especially for a round trip over the internet. Nginx is used this way all the time. In fact, this technique is so common, and widely used, that it even has a name: reverse proxy. There are [many benefits](http://en.wikipedia.org/wiki/Reverse_proxy) beyond just the resolution of your particular issue.
Marcelo Cantos
Sadly the title of this question involves asking how I could use the *"ReverseProxyProtocol"* on Twisted. I am interested in applying Twisted's *built-in* ReverseProxy mechanism. I am not saying reverse_proxy is inefficient, I am saying that if I can get twisted to do the reverse proxy it would be much more cleaner.
disappearedng
@user140330: Fair point; if you want to use Twisted's facility, that's your prerogative. But I disagree that putting nginx in front is a less clean option. In many respects, it is a cleaner option, since it separates the process that owns state (your Twisted web server) from the process that owns the listening socket, making it much easier to reconfigure your systems in production without having to shut everything down. This is just one of the benefits I alluded to.
Marcelo Cantos
True, I agree with you. The problem with what I am doing is: Twisted has too few users for this particular part. It is almost impossible to get help. Nginx is very effective in doing what they have been doing and has been optimized very well. I realized that using a popular tool is a much better option with the community support + efficiency. By the way, I will be using haproxy since nginx doesn't support my operations.
disappearedng
Cool. I hadn't taken a good look at HAProxy before; now I have, and I'm quite impressed!
Marcelo Cantos