Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Long polling in Yesod

Can I do long polling in Yesod, or any other Haskell web framework with comparable database facilities?

To be precise, I want to delay a HTTP response until something interesting happens. There should also be a timeout after which the client will be served a response saying "nothing happened" and then the client will issue the same request.

To make life even more complicated, the app I have in mind is serving all its stuff over both HTTP/HTML5 and a really compact UDP protocol to MIDP clients. Events from either protocol can release responses in either protocol.

TIA, Adrian.

like image 234
Adrian May Avatar asked Jun 10 '13 11:06

Adrian May


People also ask

What is long polling technique?

Long polling is a technique to retrieve updated information from the server at a known time interval. Upon receiving new information, you can swap it into a known target element, and a user perceives that information is updating in near real-time. The method has its advantages and drawbacks.

What is long polling in rest?

Long polling is a method that server applications use to hold a client connection until information becomes available. This is often used when a server must call a downstream service to get information and await a result.

Where is long polling used?

HTTP Long polling is a mechanism where the server can send data independently or push data to the client without the web client making a request. The information is then pushed as it becomes available, which makes it real-time. However, it works best if the messages from the server are rare and not too frequent.


2 Answers

I can't answer all the issues of the more complicated UDP stuff, but the short answer is that, yes, Yesod supports long polling. You can essentially do something like:

myHandler = do
    mres <- timeout timeoutInMicroseconds someAction
    case mres of
        Nothing -> return nothingHappenedResponse
        Just res -> doSomething res

You'll probably want to used System.Timeout.Lifted from the lifted-base package.

like image 77
Michael Snoyman Avatar answered Oct 25 '22 20:10

Michael Snoyman


Michael's answer hits the timeout requirement. For general clients you do not want to keep HTTP responses waiting for more than about 60 seconds as they may be connecting through a proxy or similar which tend to get impatient after about that long. If you're on a more tightly controlled network then you may be able to relax this timeout. One minor correction is that the parameter to timeout is in microseconds not nanoseconds.

For the 'wait for something interesting to happen' part, we use the check combinator from Control.Concurrent.STM (which wraps up retry) so our handler thread waits on a TVar:

someAction = do
    interestingStuff <- atomically $ do
        currentStuff <- readTVar theStuff
        check $ isInteresting currentStuff
        return currentStuff
    respondWith interestingStuff

Meanwhile, other threads (incl HTTP handlers) are updating theStuff :: TVar Stuff - each update triggers a new calculation of isInteresting and potentially a response if it returns True.

This is compatible with serving the same information over UDP: simply share theStuff between your UDP server threads and the Yesod threads.

like image 31
Dave Turner Avatar answered Oct 25 '22 18:10

Dave Turner