C# – Polling vs Push Notifications in ASP.NET and SQL Server

asp.netciisMySQLsql server

I have a hybrid web app for android. The webpage or website the app shows is in asp.net. The javascript for the webpage running in the webview of the app is sending out an ajax request every 10 seconds to an asp.net page which queries a database server for refreshed data and returns the needed values as a result of the ajax call. Note, this is expected to be a very high volume site.

Often the data will be the same. I am considering using push notifications instead of the page having to poll every 10 secs, so that data is only sent when it is different. I am looking into what is called SignalR to do this and it doesn't look that bad.

What I want is a solution that is the least overhead to the web server (IIS8) and the database server (Sql Server 2014). So if push notifications are sent out, I think the web server would have to keep track of each launched instance of the webpage as a session rather than every page instance being static and stateless as it normally is.

So what does this mean to the web server and database server in terms of using up processing time and resources? Is it more efficient for the web server to create and manage all of these sessions than it is for the web server and database server to handle polling requests from everyone?

To be clear, imagine polling for a delivery driver's location and the driver's stops. The driver's stops might not change at all or only occasionally, but the driver will change every time his or her location changes. Should I poll for all info every 10 secs so that any changes are guaranteed to be picked up, or should only the info that needs to be sent be sent out and only when it needs to be sent?

Thanks in advance for your opinions and advice.

Best Answer

Events and Subscribers

When you make the shift from polling to event notifications, the best way to think about it is in terms of events and subscribers.

In your concept, you imagine the web server maintaining a session state for each instance of the client, and effectively polling the database on its behalf in order to know when to send the notification to the client.

You are right to be concerned about the impact on server resources of this approach! You haven't yet fully leveraged the power of notifications, you've just shifted where the polling happens.

A more effective way is for clients to register themselves to receive a notification when a particular piece of data changes. Then, when that data changes, publish a notification that the data has changed. Let the notification framework identify who has registered to receive a notification (subscribed) and to let them know.

One way to do this with signalr is through 'groups'. Exactly how it should be structured depends on your data model, but using your example, you could have a group per driver. A simplified view of the sequence:

  1. The client app starts and initiates a connection to the signalr endpoint
  2. The client app subscribes to notifications about a particular driver
    1. There are many ways to do this, but if you are using signalr, you can directly call server methods from the client
    2. The server would add the client into a group for the requested driver
  3. When the driver reports a new location, tell signalr to send a message to the group for that driver
    1. Strictly speaking in signalr, this is done by invoking a client side method from the server
    2. The client now has the updated info and can refresh the page
    3. If there are no clients registered in the group, signalr will do nothing
    4. If there are multiple clients registered in the group, signalr will invoke the same method (with arguments) on all of them
    5. You can further decouple the 'write operation' which updates the data from the code which sends the notification via signalr through a concept such as domain events

This way you receive notifications on the client, without polling anywhere.

Edit to add - Efficiency

Following your comment, a few notes on efficiency using your example of a chat application:

With polling approach, you are using the following resources:

  • storage (db/memory):
    • list of who is talking to who
    • chat message history with appropriate metadata so that the poll request can identify new messages since the last request
  • computation
    • handling new messages pushed in by the client - storing them appropriately
      • you'd have one request per new chat message
    • handling poll requests by the clients - querying for new messages and returning them - would happen on every poll from every client
      • if you have 500 clients, some of whom are idle, you'd still have 50 requests per second

Scalability:

  1. Your storage load grows with number of active clients, and with chat activity
  2. Your compute load grows with message chat activity and with number of connected clients

With a signalr notification approach, you have:

  • storage
    • list of who is talking to who (signalr will do this for you for free with it's 'group' system
    • chat messages (optional - only if you want a chat log on the server - and could be persisted asynchronously)
  • computation
    • handling new messages pushed in by the client, which includes asking signalr to propagate them to the members of the group
      • one request per new chat message

Scalability:

  1. Your storage load grows with the number of active clients only
  2. Your compute load grows with message chat activity only

Based on that, I think the notification approach is more efficient. As you can see, while signalr will maintain the group membership list, you have to do that anyway even if you go down a polling approach.

Terminology Note

  • Push Notifications have a well defined meaning in this space, which permits sending a notification via the mobile device's operating system, which permits the notification to appear in the device's notification list even if your app isn't running - e.g. Apple Push Service & Google Cloud Messaging. Strictly speaking, signalr won't give you that, as your app must be running to receive the signalr client invocation.