2

I'm trying to find a solution to a send email action that may take a long time and time out our load balancer which is on Rackspace. The only question I could find that relates to this specific issue is this:

keep load balancer from timing out during long operation

As I understand it I need to run another action whilst the main slow action is completing to constantly poll and return in order to keep things alive. My email action contains the following:

 var sendto = db.Users
                    .Where(b => b.Id == model.SentTo |
                    ((model.SelectedRoles.Any(s => b.Roles.Select(h => h.RoleId).Contains(s)))
                    && ((b.enrollment.Any(h => h.cohort.CourseID == model.CourseID) | model.CourseID == null))
                    && (b.OrgID == model.OrgID | model.OrgID == null))).ToList();

                    foreach (var address in sendto)
                    {
                        string Body = "message goes here";

                        EmailConfig.SendMessageViaMailGun(filestoattach, address.Email, null, email.Subject, Body);
                    }

So a list is created and then looped through with emails being sent to each person on the list. The Async method answer in the question above seems like it would do the trick but in the comments I can see this is considered a bad idea. It's also out of date in terms of how async works in the latest MVC version.

My question is what is the best way to keep this action from timing out the load balancer whilst it is completing?

Rob
  • 199
  • 21
  • 2
    You should move that logic outside of the web server. Basically your web server should queue a request (e.g. to RabbitMQ) and then a separate service running elsewhere should dequeue it and send the emails. – mjwills Oct 13 '17 at 11:55

1 Answers1

3

This has nothing to do with async really, it is an infrastructure issue.

There are two ways to perform long operations:

  1. The proper way: have a backend server and a process running there + communicate to this backend process via queuing (or database polling), then the client updates based on the progress (stored in some database) and update the UI on the web server. You also need to track the progress on the backend to continue on case of unexpected shutdown.

  2. The cheap way: Spin a different thread (or task) on the web server, and have it perform the operation, and poll from javascript the progress of this thread. This could however get shut down any minute (webserver recycle) and you lose the operation (if you are ok with this), then you need to pick up the operation and continue. A crude way would be to just wrap the whole thing you have with Task.Run, and return right away, then query the progress from Javascript, but as I said above this is prone to interruptions.

albattran
  • 1,887
  • 1
  • 12
  • 16
  • Hello, thanks for your answer. So if I for example set things up so that the email list was put into a table which was then updated as the emails were sent out and when the action began I used signalR to check this every 5 seconds and send back a message to the page updating on the progress before ceasing operations once it could see there were no messages left to end this would effectively be what you are talking about in 1? This would also keep the load balancer from timing out also? – Rob Oct 16 '17 at 11:00