multithreading - 执行需要 5 秒的操作(如发送电子邮件)但立即返回并回复?
问题描述
语境
在 ASP.NET Core 应用程序中,我想执行一个需要 5 秒的操作(比如发送电子邮件)。我确实知道 async/await 及其在 ASP.NET Core 中的用途,但是我不想等待操作结束,而是想立即返回给客户端。
问题
因此,无论是自制软件,还是 Hangfire 的,它都有点像 Fire and ForgetBackgroundJob.Enqueue<IEmailSender>(x => x.Send("hangfire@example.com"));
假设我有一些更复杂的方法,注入了 ILogger 和其他东西,我想触发并忘记该方法。该方法中有错误处理和日志记录。(注意:对于 Hangfire 来说不是必需的,这个问题与后台工作人员的实现方式无关)。我的问题是该方法将完全脱离上下文运行,内部可能没有任何作用,没有 HttpContext(我的意思是 HttpContextAccessor 会给出 null 等)所以没有用户,没有会话等。
问题
如何正确解决这个特定的电子邮件发送问题?没有人想要等待 5 秒的响应,同时没有人想要抛出和发送电子邮件,如果发送操作返回错误,甚至不记录......
解决方案
如何正确解决这个特定的电子邮件发送问题?
这是“从我的 Web 应用程序运行后台作业”问题的特定实例。
没有通用的解决方案
有——或者至少有一个普遍的模式;只是许多开发人员试图避免它,因为它并不容易。
我在关于基本分布式架构的博文系列中对其进行了非常完整的描述。我认为要承认的一件重要事情是,由于您的后台工作(发送电子邮件)是在 HTTP 请求之外完成的,因此它确实应该在您的 Web 应用程序进程之外完成。一旦你接受了这一点,剩下的解决方案就到位了:
- 您需要一个持久的存储队列来完成这项工作。Hangfire 使用您的数据库;我倾向于喜欢 Azure 存储队列等云队列。
- 这意味着您需要复制所有需要的数据,因为它需要序列化到该队列中。同样的限制也适用于 Hangfire,只是因为 Hangfire 在同一个 Web 应用程序进程中运行,所以并不明显。
- 您需要一个后台进程来执行您的工作队列。我更喜欢 Azure Functions,但另一种常见的方法是将ASP.NET Core Worker 服务作为 Win32 服务或 Linux 守护程序运行。Hangfire 有自己的临时进程内线程。在进程内运行 ASP.NET Core 托管服务也可以,尽管它与 Hangfire 有一些相同的缺点,因为它也在 Web 应用程序进程中运行。
- 最后,您的工作队列处理器应用程序有自己的服务注入,如果需要,您可以对其进行编码以创建每个工作队列项的依赖范围。
IMO,这是随着您的 Web 应用程序“成长”而达到的正常阈值。它比简单的 Web 应用程序更复杂:现在您有了一个 Web 应用程序、一个持久队列和一个后台处理器。因此,您的部署变得更加复杂,您需要考虑诸如对工作队列模式进行版本控制这样的事情,这样您就可以在不停机的情况下进行升级(Hangfire 无法很好地处理)等等。一些开发人员对此非常犹豫,因为当“他们想要做的只是发送一封电子邮件而不等待它,但事实是,当一个婴儿网络应用程序被分发时,这是向上的必要步骤。
推荐阅读
- azure-ad-b2c - 受邀来宾用户能否使用 Azure AD B2C 登录?
- mysql - MySql:加载产品目录:在 Windows 7 上加载产品目录时遇到错误
- audio - 合并 2 个文件(音频和视频),在 FFMPEG 中带有 BITC 和水印
- android - Kotlin 在应用函数中分配属性后返回具有未分配属性的对象
- cakephp - 如何在 CakePHP 1.3 中修改 $content_for_layout
- azure - 如何将 CNAME 从多个插槽合并到通配符表达式
- python - 显式等待不适用于基于 Angular 的 PayPal 沙箱
- google-bigquery - BigQuery:是否可以通过在记录中添加字段来修改表架构
- java - 按数组内对象内的内容对数组进行排序
- javascript - 如何在 IE11 中将 svg 转换为图像