Using SignalR to notify clients when scheduled events occur - asp.net-mvc

I'm developing an ASP.NET MVC 5 application that displays current staffing data, and uses SignalR to notify connected clients when staffing changes occur. This is working great for real-time events ("I need to leave work now."), but now I need to handle scheduled events where a staffing change will happen in the future.
That is, an event may be scheduled to occur in 3 hours and 27 minutes ("I need to leave work at 4pm") or even 3 months from now. When the event occurs, connected clients should be notified in order to display correct staffing data to the end users. Of course, the future may change, and a solution would need to account for scheduled events being canceled or modified.
I would love to find a clean way to do this that doesn't involve frequent polling from clients to learn of upcoming events, a thread on the server side that sleeps, etc.

I would create a small windows service that takes care of scheduling. Then use a service bus to signal the web server for example
http://ayende.com/blog/3752/rhino-service-bus
On the web server you can use https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy
to forward the messages directly to the clients

Related

Is SignalR overkill for simple notifications on async tasks?

The current .NET MVC 5 web app includes a button somewhere which calls into a controller method which generates an SSRS report and then emails that to some recipients (with the proper layers but it's still one request).
After labeling this a long-running task, we've switched to using HangFire to kick off a background task. So now the controller just schedules the background task and returns a "Task started" message to the user.
As the task progresses, we want to notify the user of the task results. Searching for modern ways to do this in a .NET environments we decided to try out SignalR and its simplicity has led to a quick and easy implementation of async server-triggered notifications on the client.
Is this an overengineered application of SignalR? Would it be a better idea to just check for new alerts ones whenever the user refreshes the page? Are we wasting resources on SignalR or is the library efficient even for about 10-20 messages per hour?
I'd say you're fine up to 3 updates per second - and even then you could go faster with caveats. And yes, you can easily handle hundreds on a single node.
SignalR looks ideal for your solution. It should be used by any ASP.NET site that needs real time updates.

In asp.net-mvc, what is the correct way to do expensive operations without impacting other users?

I asked this question about 5 years ago around how to "offload" expensive operations where the users doesn't need to wait for (such as auditng, etc) so they get a response on the front end quicker.
I now have a related but different question. On my asp.net-mvc, I have build some reporting pages where you can generate excel reports (i am using EPPlus) and powerpoint reports (i am using aspose.slides). Here is an example controller action:
public ActionResult GenerateExcelReport(FilterParams args)
{
byte[] results = GenerateLargeExcelReportThatTake30Seconds(args);
return File(results, #"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "MyReport.xlsx");
}
The functionality working great but I am trying to figure out if these expensive operations (some reports can take up to 30 seconds to return) are impacting other users. In the previous question, I had an expensive operation that the user DIDN"T have to wait for but in this case he does have to wait for as its a syncronoous activity (click Generate Report and expectation is that users get a report when its finished)
In this case, I don't care that the main user has to wait 30 seconds but i just want to make sure I am not negatively impacting other users because of this expensive operation, generating files, etc
Is there any best practice here in asp.net-mvc for this use case ?
You can try combination of Hangfire and SignalR. Use Hangfire to kickoff a background job and relinquish the http request. And once report generation is complete, use SignalR to generate a push notification.
SignalR notification from server to client
Alternate option is to implement a polling mechanism on client side.
Send an ajax call to enque a hangfire job to generate the report.
And then start polling some api using another ajax call that provides status and as soon report is ready, retrieve it. I prefer to use SignalR rather than polling.
If the report processing is impacting the performance on the web server, offload that processing to another server. You can use messaging (ActiveMQ or RabbitMQ or some other framework of your choice) or rest api call to kick off report generation on another server and then again use messaging or rest api call to notify report generation completion back to the web server, finally SignalR to notify the client. This will let the web server be more responsive.
UPDATE
Regarding your question
Is there any best practice here in asp.net-mvc for this use case
You have to monitor your application overtime. Monitor both Client side as well as server side. There are few tools you can rely upon such as newrelic, app dynamics. I have used newrelic and it has features to track issues both at client browser as well as server side. The names of the product are "NewRelic Browser" and "NewRelic Server". I am sure there are other tools that will capture similar info.
Analyze the metrics overtime and if you see any anomalies then take appropriate actions. If you observe server side CPU and memory spikes, try capturing metrics on client side around same timeframe. On client side if you notice any timeout issues, connection errors that means your application users are unable to connect to your app while the server is doing some heavy lifting. Next try to Identify server side bottlenecks. If there is not enough room to performance tune the code, then go thru some server capacity planning exercise and figure out how to further scale your hardware or move the background jobs out of the web servers to reduce load. Just capturing metrics using these tools may not be enough, you may have to instrument (log capturing) your application to capture additional metrics to properly monitor application health.
Here you can find some information about capacity planning for .net application from Microsoft.
-Vinod.
These are all great ideas on how to move work out of the request/response cycle. But I think #leora simply wants to know whether a long-running request will adversely impact other users of an asp.net application.
The answer is no. asp.net is multi-threaded. Each request is handled by a separate worker thread.
In general it could be considered a good practice to run long running tasks in background and give some kind of notification to user when the job is done. As you probably know web request execution time is limited to 90 seconds, so if your long running task could exceed this, you have no choice but to run in some other thread/process. If you are using .net 4.5.2 you can use HostingEnvironment.QueueBackgroundWorkItem for running long running tasks in background and use SignalR to notify user when the task is finished the execution. In case that you are generating a file you can store it on server with some unique ID and send to user a link for downloading it. You can delete this file later (with some windows service for example).
As mentioned by others, there are some more advanced background task runners such as Hangfire, Quartz.Net and others but the general concept is the same - run task in backround and notify user when it is done. Here is some nice article about different oprions to run background tasks.
You need to use async and await of C#.
From your question I figured that you are just concerned with the fact that the request can be taking more resources than it should, instead of with scalability. If that's the case, make your controller actions async, as well as all the operations you call, as long as they involve calls that block threads. e.g. if your requests go through wires or I/O operations, they will be blocking the thread without async (technically, you will, since you will wait for the response before continuing). With async, those threads become available (while awaiting for the response), and so they can potentially serve other requests of other users.
I assumed you are not wandering how to scale the requests. If you are, let me know, and I can provide details on that as well (too much to write unless it's needed).
I believe a tool/library such as Hangfire is what your looking for. First, it'll allows for you to specify a task run on a background thread (in the same application/process). Using various techniques, such as SignalR allows for real-time front-end notification.
However, something I set up after using Hangfire for nearly a year was splitting our job processing (and implementation) to another server using this documentation. I use an internal ASP.NET MVC application to process jobs on a different server. The only performance bottleneck, then, is if both servers use the same data store (e.g. database). If your locking the database, the only way around it is to minimize the locking of said resource, regardless if the methodology you use.
I use interfaces to trigger jobs, stored in a common library:
public interface IMyJob
{
MyJobResult Execute( MyJobSettings settings );
}
And, the trigger, found in the front-end application:
//tell the job to run
var settings = new MyJobSettings();
_backgroundJobClient.Enqueue<IMyJob>( c => c.Execute( settings ) );
Then, on my background server, I write the implementation (and hook in it into the Autofac IOC container I'm using):
public class MyJob : IMyJob
{
protected override MyJobResult Running( MyJobSettings settings )
{
//do stuff here
}
}
I haven't messed too much with trying to get SignalR to work across the two servers, as I haven't run into that specific use case yet, but it's theoretically possible, I imagine.
You need to monitor your application users to know if other users are being affected e.g. by recording response times
If you find that this is affecting other users, you need to run the task in another process, potentially on another machine. You can use the library Hangfire to achieve this.
Using that answer, you can declare a Task with low priority
lowering priority of Task.Factory.StartNew thread
public ActionResult GenerateExcelReport(FilterParams args)
{
byte[] result = null;
Task.Factory.StartNew(() =>
{
result = GenerateLargeExcelReportThatTake30Seconds(args);
}, null, TaskCreationOptions.None, PriorityScheduler.BelowNormal)
.Wait();
return File(result, #"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "MyReport.xlsx");
}
Queue the jobs in a table, and have a background process poll that table to decide which Very Large Job needs to run next. Your web client would then need to poll the server to determine when the job is complete (potentially by checking a flag in the database, but there are other methods.) This guarantees that you won't have more than one (or however many you decide is appropriate) of these expensive processes running at a time.
Hangfire and SignalR can help you here, but a queueing mechanism is really necessary to avoid major disruption when, say, five users request this same process at the same time. The approaches mentioned that fire off new threads or background processes don't appear to provide any mechanism for minimizing processor / memory consumption to avoid disrupting other users due to consuming too many resources.

Should i make a seperate app to send push notifications to 40-50k users in RoR App or use background jobs

I have a rails application that is in fact a backend of a popular IOS application which have a user base of 200k users who needs to be notified time to time.
Daily 40-50k users will be notified using push notifications. These push notifications will be realtime and scheduled ones. eg: if a new users signs up he will be notified within few seconds. eg: scheduled notifications will run at 10 pm daily with limited users ranging 10k-30k or sometimes more upto 100k.
I also will be doing business reporting to generate list of users fulfilling certain criteria and it requires firing mysql queries that could take upto 1-2 minutes of time.
My area of concern is should i have a seperate application with seperate mirror db to send push notifications to these users so my IOS users doesnt feel lag while using this application when push notifications are triggered or business reporting query is triggered.
Or should i use background jobs like Rails Active job, Sidekiq or Sucker Punch to perform push notifications and triggering business reporting queries.
Is background jobs in rails so powerful that it can manage this condition and doesn't let App users to feel lag in experience.
My application stack is:
Rails: 4.1.6
Ruby: 2.2
DB: Mysql
PaaS: AWS Elastic Beans
IOS Push gem: Houston
In my opinion, there are several factors that affect my decision.
1. Does your service need to keep many persistent connections?
If your answer is YES, then use another language which has better asynchronous IO (like Node.js) to implement your push service.
If your answer is NO, which means you only send requests to third-party services (like APNS), then consider the next factor.
2. Do you have to reuse your domain model in your push service?
If your answer is YES, then stick to Active Job + Sidekiq.
If your answer is NO, which means you only uses some fields (like id, name) of some table (like users), then consider the next factor.
3. Does your server have a limited memory resource?
A rails processes often consumes several hundreds of MB of memory, and Sidekiq requires a separate Rails process which can't be preforked (which means it does not share memory with your Rails app).
So if your answer is YES, then consider create a separate lightweight push service.
As for mirror database, if I have to do heavy query before push, I will definitely use mirror database.

How do I spread out load on my rails app from webhook responses?

I have a rails app that easily handles the traffic we currently experience, except once a day when we receive a large number of pings within a few seconds from an external service's webhook that is reporting on past transactions. Currently this causes the app to time out due to lack of db connection availability, meaning we lose some of the webhooks as well as bringing the site down for a few seconds. It's not important that the data contained in these webhooks be processed instantaneously, so I am looking for a good way to spread out the responses, rather than do an expensive upgrade just to handle these bursts with additional db connection capability.
Is it okay to just have the relevant controller method sleep for a small, random number of seconds before doing anything that would open a db connection to spread things out? Or is there a better way to do this?
Setup a background/async processing system like Sidekiq (or whatever Heroku offers). Modify your controller action to do nothing but shove the parameters into a background job and return "ok". Then process the job in the background.

concurrent application

i have used erlang for the passed five month and i have liked it now it is my time to write down a concurrent application that will interact with the YAWS web server and mnesia DBMS and to work on a distributed system may any one help me with a sketchy draft in Erlang?
i mean the application should have both the sever end and the client end where by the server can accept subscriptions from clients, Forwards notifications from event processes to each of the subscribers, accept messages to add events and start the needed processes, can accept messages to cancel an event and subsequently kill the event processes. whereas the client should be able to ask the server to add an event with all its details,ask the server to cancel an event, monitors the server (to know if it goes down) and shut down the event server if needed. The events requested from the server should contain a deadline
Spend some time browsing github, you can find projects corresponding to your description:
http://www.google.ca/search?hl=en&biw=1405&bih=653&q=site%3Agithub.com+erlang+yaws+mnesia&aq=f&aqi=&aql=&oq=

Resources