views:

721

answers:

2

I'm trying to implement comet style features by polling the server for changes in data and holding the connection open untill there is something to response with.

Firstly i have a static variable on my controller which stores the time that the data was last updated:

public static volatile DateTime lastUpdateTime = 0;

So whenever the data i'm polling changes this variable will be changed.

I then have an Action, which takes the last time that the data was retrieved as a parameter:

public ActionResult Push(DateTime lastViewTime)
{
    while (lastUpdateTime <= lastViewTime)
    { 
        System.Threading.Thread.Sleep(10000);
    }
    return Content("testing 1 2 3...");
}

So if lastUpdateTime is less than or equal to the lastViewTime, we know that there is no new data, and we simply hold the request there in a loop, keeping the connection open, untill there is new information, which we could then send back to the client, which would handle the response and then make a new request, so the connection is essentially always open.

This seems to work fine but i'm concerned about thread safety, is this OK? Does lastUpdateTime need to be marked as volatile? Is there a better way?

Thanks

edit: perhaps i should use a lock object when i update the time value

private static object lastUpdateTimeLock = new object();

..

lock (lastUpdateTimeLock)
{
    lastUpdateTime = DateTime.Now;
}
+1  A: 

Honestly my concern would be with the number of connections kept open and the empty while loop. The connections you're probably fine on, but I'd definitely want to do some load testing to be sure.

The while (lastUpdateTime <= lastViewTime) {} seems like it should have a Thread.Sleep(100) or something in there. Otherwise I'd think it would consume a lot of cpu cycles needlessly.

The lock does not seem necessary to me around lastUpdateTime = DateTime.Now since the previous value does not matter. If it were lastUpdateTime = lastUpdateTime + 1 or something, then maybe it would be.

David Hogue
yeah, i thought of sleeping the thread in the loop too, that would be very sensible. I'm interested to know what will happen if two thread attempted to modify lastUpdateTime concurrently and about how others approach this style of reverse AJAX with long polling.
Paul Creasey
Generally it's not a problem if two threads set a variable. One thread will set it and the other thread will overwrite it later. You would want a lock if the new value is based off the previous value or if you are checking the value before doing something.As far as reverse AJAX, I don't have much experience personally. I have heard of techniques similar to yours and it looks like it should work. I have also heard there are some specially designed web servers dedicated to serving those requests instead of tying IIS up with open HTTP connections since it was not really designed for that.
David Hogue
@David, there's a lot of additional work to get a different server running and integrated well (setup, different ports, different languages often, crazy APIs and callbacks, etc), and since IIS actually does work phenomenally well for this purpose, it makes great sense to use it. The problem is, IIS has a bad reputation because people try to implement it...well, the way the OP described (no offense Paul). That method fails quite quickly, as mentioned in my answer, but there are other methods that allow IIS to scale very well, and then integration becomes a snap. Anyway, just an FYI :)
jvenema
+3  A: 

Regarding your original question, you do have to be careful with DateTimes, since they're actual objects in the .NET runtime. Only a few data types can be natively accessed (eg ints, bools) without locking (assuming you're not using Interlocked). If you want to avoid any issues with Datetimes, you can get the ticks as a long and use the Interlocked class to manage them.

That said, if you're looking for comet capabilities in a .NET application, you're unfortunately going to have to go a lot further than what you've got here. IIS/ASP.NET won't scale with the approach you've got in place right now; you'll hit limits before you even get to 100 users. Among other things, you will have to switch to using async handlers, and implement a custom bounded thread pool for the incoming requests.

If you really want a tested solution for ASP.NET/IIS, check out WebSync, it's a full comet server designed specifically for that purpose.

jvenema
Would it perhaps be more reasonable to have a JavaScript timer which calls an service via ajax every few minutes? I think a couple of minutes delay would be quite reasonable for the appiclation.
Paul Creasey
I should add that this site is never going to be heavily loaded, probably 15 users concurrently max.
Paul Creasey
If a few minutes delay are acceptable, then yes, that's a perfectly fine solution, especially given that you're not dealing with too many users. Still need to be careful with the threading though, you definitely want to go with either the locking method you described or ticks/interlocked method I mentioned, or you will run into concurrency issues at some point, regardless of the load.
jvenema