发送电子邮件无需等待

huangapple go评论73阅读模式
英文:

Send e-mail without waiting

问题

我的系统 (.Net 4.8) 发送电子邮件,今天在每个调用之前都有await。它能正常工作,但每封电子邮件发送都需要一些时间,与此同时用户一直在等待。

为了加快这个过程,我们尝试在那一行应用了_ =,但最终我们收到了这个错误:

> 在仍有异步操作挂起的情况下,异步模块或处理程序已完成

我还尝试了这种方法 Task.Run,但然后SendEmailMessage甚至都不会运行。

经过一些研究,我明白了 ASP.NET 在这种情况下不起作用(参考:这里这里)。由于所有请求都已完成,因此没有必要继续进行该过程;所以当主进程 CreateNewProduct 完成时,SendEmailMessage 仍在进行中,但也已终止。

我想知道是否有办法使 .Net 在这种情况下工作。也许可以创建一个新的堆栈或其他东西来处理这些异步进程?我看到了一些建议,比如使用 RabbitMQ,但我不想运行额外的服务。

public async Task<JsonResult> CreateNewProduct(string productID){
    
    // 代码在这里

    // 当前方法 (多封电子邮件)
    await SendEmailMessage(messageBody1);
    await SendEmailMessage(messageBody2); 
    await SendEmailMessage(messageBody3); 

    // 新方法 1
    _ = SendEmailMessage(messageBody1);

    // 新方法 2
    Task.Run(() => SendEmailMessage(messageBody1));
    
    return Json(new
    {
        success = true,
    }, JsonRequestBehavior.AllowGet);
}

public async Task SendEmailMessage(string messageBody){
    
    using (var client = new MailKit.Net.Smtp.SmtpClient())
    {
        client.ServerCertificateValidationCallback = (s, c, h, e) =>
        {
            Console.WriteLine(e);
            return true;
        };
        await client.ConnectAsync(_SMTPserver, _SMTPport, true);
        await client.AuthenticateAsync(_address, _password);
        await client.SendAsync(messageBody);
        client.Disconnect(true);
    }
}
英文:

My system (.Net 4.8) sends e-mail, and today we have await before each call. It works fine but takes some seconds to send each e-mail, meanwhile user just keeps waiting.

Trying to speed up this proccess, we tried to apply _ = to that line, but then eventually we got this error:

> An asynchronous module or handler completed while an asynchronous operation was still pending

I've also tried this other approach Task.Run but then SendEmailMessage wouldn't even run.

After some research I've understood that ASP.NET doesn't work well under this circustances (reference: here and here). Since all request have being fulfilled there is no need to keep that process ongoing; so when the main process CreateNewProduct finishes, SendEmailMessage still is in progress but is also terminated.

I was wondering if there is a way to make .Net work with this situation. Maybe to create a new stack or something to process these async process? I did see some suggestions like to use RabbitMQ but I wouldn't like to have additional services running.

public async Task<JsonResult> CreateNewProduct(string productID){

    //Code here

    //current approach (several e-mails)
    await SendEmailMessage(messageBody1);
    await SendEmailMessage(messageBody2); 
    await SendEmailMessage(messageBody3); 

    //new approach 1
    _ = SendEmailMessage(messageBody1);

    //new approach 2
    Task.Run(() => SendEmailMessage(messageBody1));

    return Json(new
    {
        success = true,
    }, JsonRequestBehavior.AllowGet);
}

public async Task SendEmailMessage(string messageBody){

    using (var client = new MailKit.Net.Smtp.SmtpClient())
    {
        client.ServerCertificateValidationCallback = (s, c, h, e) =>
        {
            Console.WriteLine(e);
            return true;
        };
        await client.ConnectAsync(_SMTPserver, _SMTPport, true);
        await client.AuthenticateAsync(_address, _password);
        await client.SendAsync(messageBody);
        client.Disconnect(true);
    }
}

答案1

得分: 1

如果您想知道电子邮件是否已实际发送,您必须等待。这是无法避免的。但是,您可以同时发送多封电子邮件(假设对SendEmailMessage的并发调用不共享资源):

var task1 = SendEmailMessage(messageBody1);
var task2 = SendEmailMessage(messageBody2); 
var task3 = SendEmailMessage(messageBody3);

await Task.WhenAll(task1, task2, task3);

然而,如果您想要发送数百或数千封电子邮件,您将不得不组织一种带有后台处理的队列。

英文:

If you want to know if email was actually sent, you have to wait. There is no way around it. However, you can send several emails at the same time (assuming concurrent calls to SendEmailMessage share no resources):

var task1 = SendEmailMessage(messageBody1);
var task2 = SendEmailMessage(messageBody2); 
var task3 = SendEmailMessage(messageBody3);

await Task.WhenAll (task1, task2, task3);

However, if you'd want to send hundreds or thousands, you'd have to organize some kind of queue with background processing.

答案2

得分: 0

For now, what I managed to do is an updated code and start studying more about Hangfire and Quartz.NET for future improvements.

public async Task<JsonResult> CreateNewProduct(string productID){

//Code here

try
{
    _ = Task.Run(() =&gt; SendEmailMessage(messageBody));
}
catch (Exception ex)
{
    //Deal with exception
}

return Json(new
{
    success = true,
}, JsonRequestBehavior.AllowGet);

}

英文:

For now, what I managed to do is an updated code and start studying more about Hangfire and Quartz.NET for future improvements.

public async Task&lt;JsonResult&gt; CreateNewProduct(string productID){

    //Code here

    try
    {
        _ = Task.Run(() =&gt; SendEmailMessage(messageBody));
    }
    catch (Exception ex)
    {
        //Deal with exception
    }

    return Json(new
    {
        success = true,
    }, JsonRequestBehavior.AllowGet);
}

huangapple
  • 本文由 发表于 2023年6月8日 05:05:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427109.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定