Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Long polling with Nancy Async Beta

Normally I would use SignalR to handle any data pushing but in this case I'm using a self-hosted instance of Nancy Async Beta on the server end. I've heard its still possible to use SignalR in this scenario but I would still prefer to handle the long-polling myself in this case. Here is the code from a simple experiment app I'm writing that produces the issue described below:

        Get["/receivechat", true] = async (x, ct) =>
            {
                string result = await _massPublisher.WaitForResult("test");
                return result;
            };

This handles the actual long-polling requests. The requests seem to enter this lambda in chunks of 4 or 5. So for example if I put a break point on the very first line of the lambda I wont see that breakpoint get hit until I send in 4 or 5 more requests and then suddenly all of the requests enter the lambda all at once. Obviously I need them to all enter as they're requested so they can all await my WaitForResult method. The WaitForResult method simply awaits a common TaskCompletionSource. I can post that code and the client-side code if necessary. As far as I can tell it's seems to be a problem with how I'm using Nancy Async Beta since the requests are being handled in parallel and the requests wont even enter the lambda until a few other requests are made.

It's probably note worthy that this application is still responsive to all other requests during this time.

I've read the documentation I can find on Nancy Async Beta and it looks like this example should work...but it's not - for me anyway. If anyone can offer some insight on why this doesn't work it would be much appreciated. And like I said I can post more code from this experiment but for now it seemed it would just clutter the question.

Update: Since I'm relatively new to the TPL and Nancy I've taken my code out of the experiment in order to isolate the issue and troubleshoot a little more. Here is the code I've updated to. It simply awaits a Task Delay of 5 seconds and then sends the current time to the client.

        Get["/receivechat", true] = async (x, ct) =>
            {
                //string result = await _massPublisher.WaitForResult("test");
                //return result;
                await Task.Delay(5000);
                return DateTime.Now.ToString();
            };

My understanding is that each request will be processed in parallel and independent of each other. Now with that understanding I would think each client should see a reply every 5 seconds regardless of how many other clients are polling those requests. However, here are the results:

async illustration

So in other words, a response is sent every 5 seconds but only to one client at a time. So for 3 clients it takes each client 15 seconds to receive its response. For 2 = 10 seconds etc...

So far I cant see what I'm doing wrong. Which is why I'm here. I love finding out I'm wrong! :) I'll get to learn something new. So if you know or may know where I'm going wrong please let me know. I've probably missed something small and dumb that I've overlooked while looking for it many times & hopefully it's a mistake that other people will find useful.

like image 354
Stewart Anderson Avatar asked Apr 15 '13 23:04

Stewart Anderson


1 Answers

Figured out the problem with much appreciated help from Steven Robbins. It was the browser not sending more than one pending request at a time but I had seen this work before with all browsers including Chrome which is what I'm using to test. The browser will make multiple concurrent connections to a server BUT those requests need to be unique (apparently). If Chrome sees a pending request that exactly matches a request it's about to send out it will wait until the pending request finishes causing the exact output illustrated in the question since the other clients were more windows of the same browser (see the image in the question and description).

So by changing the commented line of JS (below) to the line above it (mainly to fix a caching issue) it also fixed the long-polling issue and suddenly both of my examples in the question work great.

            $.get("/receivechat?_=" + new Date().getTime(), null, function (data)
            //$.get("/receivechat", null, function (data)
            {
                self.viewModel.chatLines.push(data);
                self.update();
            }).error(function ()
            {
                setTimeout(self.update, 2000);
            });
like image 113
Stewart Anderson Avatar answered Nov 16 '22 20:11

Stewart Anderson