Keepalive

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Keepalive

Nolan Darilek
I'm developing an API that could benefit greatly from keepalive, and I'm curious if or how Dispatch handles this?

In telnet-based tests, the connection to the server remains open after I've completed my request. Does Dispatch automatically close and re-initiate connections after each call, or does it leave them open? If connections aren't kept alive, what needs to happen to do so, assuming such a thing is possible?
Reply | Threaded
Open this post in threaded view
|

Re: Keepalive

n8han
Administrator
Dispatch's handling of connections is the same as the underlying HttpClient's, which closely follows the HTTP spec. We tested long connections against Twitter's streaming API in the other thread and it seemed to work well. If you run into any problems just post them here. Also, if you feel like sharing any info about the API you are developing, I'd be curious. ;)

Nathan
Reply | Threaded
Open this post in threaded view
|

Re: Keepalive

Nolan Darilek
n8han wrote
Dispatch's handling of connections is the same as the underlying HttpClient's, which closely follows the HTTP spec. We tested long connections against Twitter's streaming API in the other thread and it seemed to work well. If you run into any problems just post them here.
Ah, OK, so if my server isn't closing down the connection, then Dispatch shouldn't be either? I'm guessing it keeps the request around for subsequent calls, letting the other end close it? I recognize that this is more a question about HttpClient, and I'm not actively seeing the connection to know which it is currently doing, but this is an area about which I know very little.

It isn't so much that I'm having problems, or at least not ones with Dispatch. My app needs to make calls fairly rapidly over mobile networks, possibly at the rate of 1/second, and sometimes these lag. I'll be putting in hooks to help me figure out where the lag is soon, but it occurred to me that if Dispatch is creating a new connection for each request, and if there was some method I could call somewhere to tell it to reuse connections, then that'd represent a huge optimization in this case.

Also, if you feel like sharing any info about the API you are developing, I'd be curious. ;)
Sure. The project site is http://hermesgps.info, and the in-progress API documentation is at http://hermesgps.info/doc/www/web/api/v1.wiki.

Basically, it's accessible GPS navigation for blind or visually impaired travelers. The API takes numbers for location, direction, etc. and spits back a rich JSON structure with words (current way, nearest intersection, nearby points of interest, etc.) The app is firing off these location updates pretty rapidly, and I'm seeing them resolved on the server side in half a second at most, but sometimes the app gets 10-30 seconds behind the actual position, which is especially problematic when traveling by car or bus. There are a number of factors at play here, and while I've ruled out GPS accuracy, I plan to debug network latency next and measure the time between sending a response and receiving a result. I also do semi-intelligent update caching such that updates are buffered if one is in progress, and the latest cached update is only processed if nothing is pending. It just occurred to me when doing that, though, that I'd never explicitly said that I wanted to keep my connections alive, and I didn't know if I explicitly had to, either in Dispatch or by adding any headers to my request.
Reply | Threaded
Open this post in threaded view
|

Re: Keepalive

n8han
Administrator
Nolan Darilek wrote
It isn't so much that I'm having problems, or at least not ones with Dispatch. My app needs to make calls fairly rapidly over mobile networks, possibly at the rate of 1/second, and sometimes these lag. I'll be putting in hooks to help me figure out where the lag is soon, but it occurred to me that if Dispatch is creating a new connection for each request, and if there was some method I could call somewhere to tell it to reuse connections, then that'd represent a huge optimization in this case.
Yes, by default it is creating a connection for each request. If you mix the Threads trait into the Http class you'll get the ThreadSafeClientConnManager:
http://sourced.implicit.ly/net.databinder/dispatch-http/0.7.6/dispatch/Threads.scala.html

You can also just do what Threads is doing in your own trait or subclass. Dispatch doesn't enable that connection manager by default because spinning off a connection pool, having to manage it, and eventually shut it down is a little heavyweight for many apps. Also, when I tried using it for Android programming I found it would keep trying to reuse connections that had failed and were apparently unusable.

One other thing, the pool is less than optimal for applications that are making many connections to the same endpoint; it will top out at 2 connections or some such number. This is addressed in a prerelease version of Http Commons, and we actually have a Dispatch branch tracking it already if you're interested. If you don't need to connect mostly to the same IP though I would stay on the released track.

Nathan
Reply | Threaded
Open this post in threaded view
|

Re: Keepalive

Nolan Darilek
OK, so since posting my last message, I implemented a bit of profiling in the form of short sounds played when a request starts, and when its JSON is returned to my app. Primitive, yes, but the best thing I could come up with given the nature of my app (background service tested in the field without being tethered to adb, and without being able to look at an interface.) I'm noticing that requests are taking 3 seconds or much more to process, even over wifi, and despite the fact that Lift reports that the responses are being produced in 60-70 MS. Yes, I'm on a residential cable connection, but several seconds to send a few K of JSON seems a bit extreme. :)

So, in order to use keepalive, is it only necessary that I do:

  private val http = new Http with Threads

and then use the client as I normally would? Or is there something else that I should be doing?

You note that this setup has problems with multiple connections under certain circumstances, though I was unclear on exactly what those were. My app is connecting to the same end point. It shouldn't process multiple API updates simultaneously, instead streaming them in sequence (I.e. if the GPS provides information for another update while one is in progress, then the information from that update is held for processing until the current update's processing is complete.) I'm guessing this use case isn't going to encounter the limitation you described, but I could be wrong.

I've mixed in the Threads class, but don't notice any perceptible speed-up in update processing. More than a second just to receive a few K of JSON seems a bit excessive to me. Assuming I'm not missing a step after mixing in Threads, is there any way to get more detailed logging about what's going on here so I can find from where this slowness is originating? I'm always on 3G or wifi, so I think my connection is well up to the task I'm expecting from it.

Thanks.