Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task or Thread not working/running when hosted to server

So I am trying to send email as notification to user and I want it to run asynchronously. Initially I implemented with Task.Factory.StartNew as below:

Task.Factory.StartNew(() => { _notify.NotifyUser(params); });

NotifyUser is a void method which actually sends email to the user.

But it was never executing the method. I have placed a log message inside NotifyUser method, which was never getting logged.

I followed this post and came to know that

Sometimes this kind of behaviour is an indication of an overloaded ThreadPool. Seeing as these are long running/blocking tasks, they should not be scheduled to run in the ThreadPool, which is where Task.Factory.StartNew will be sending them using the default TaskScheduler

and so I followed what was suggested there which is as below:

ThreadStart action=()=>{
    _notify.NotifyUser(params);
};
Thread thread=new Thread(action){IsBackground=true};
thread.Start();

Found no luck with the above approach too. Again I followed one more approach which even did not work.

Task task = new Task(() => {
     _notify.NotifyUser(params); 
});
task.RunSynchronously(); //or task.Start();

Is there any other way I can run this task of sending email? I've heard about async await but I read that it will not be used on void methods. Can someone let me know what would be the best approach here?


Update

ThreadPool.QueueUserWorkItem(t =>
{
   _notify.NotifyUser(params); 
});

so that it will execute this method when the thread is available. But still no luck here.

Actual Code

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddEditUser(UVModel model)
{
    if (HasPermission())
    {
         string message = string.Empty;
         bool success = false;
         string returnUrl = string.Empty;
         if (ModelState.IsValid)
         {
             using (_db = new EFDB())
             {
                   //fill user model
                   _db.Entry(user).State = state;
                   _db.SaveChanges();
                   _notify = new SendNotification();
                   _notify.NotifyUser(params); //This has to be asynchronous
                   success = true;
                   returnUrl = Url.Action("Action", "Controller", null, HttpContext.Request.Url.Scheme, HttpContext.Request.Url.Host);
                   message="success";
             }
          }
          else
                message = "Server side validation failed!";
          return Json(new { result = success, message = message, redirectUrl = returnUrl }, JsonRequestBehavior.AllowGet);
    }
    else
          return Json(new { result = false, message = "You do not have permission to perform this action!", redirectUrl = "" }, JsonRequestBehavior.AllowGet);
}

SendNotification.cs

public void NotifyUser(Parameter params)
{
    using (MailMessage mail = new MailMessage())
    {
            _db = new EFDB();
            mail.To.Add(params.toAddress);
            mail.From = params.from;

            mail.Subject = params.subject;
            mail.Body = params.body;
            mail.IsBodyHtml = true;
            mail.Priority = MailPriority.High;
            SmtpClient smtp = new SmtpClient();
            smtp.Host = "some smtp host";
            smtp.Port = 25;
            smtp.UseDefaultCredentials = false;
            smtp.EnableSsl = false;
            smtp.Credentials = new NetworkCredential("uname", "pwd");
            smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
            try
            {
                smtp.Send(mail);
            }
            catch (SmtpFailedRecipientException se)
            {
                LogError.LogMessage("SmtpFailedRecipientException Exception - " + se.Message.ToString(), context);
            }
            catch (SmtpException se)
            {
                LogError.LogMessage("SmtpException - " + se.Message.ToString(), context);
            }
    }
}
like image 411
Guruprasad J Rao Avatar asked Nov 08 '22 15:11

Guruprasad J Rao


1 Answers

You should never use StartNew unless you're doing dynamic task-based parallelism. I explain why on my blog in excruciating detail.

Assuming that you're running on ASP.NET, you should use HostingEnvironment.QueueBackgroundWorkItem. I suspect that you're seeing an exception from your delegate, and QBWI will log any exceptions to the event log.

like image 155
Stephen Cleary Avatar answered Nov 15 '22 07:11

Stephen Cleary