0

语境

在 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 秒的响应,同时没有人想要抛出和发送电子邮件,如果发送操作返回错误,甚至不记录......

4

1 回答 1

0

如何正确解决这个特定的电子邮件发送问题?

这是“从我的 Web 应用程序运行后台作业”问题的特定实例。

没有通用的解决方案

有——或者至少有一个普遍的模式;只是许多开发人员试图避免它,因为它并不容易。

我在关于基本分布式架构的博文系列中对其进行了非常完整的描述。我认为要承认的一件重要事情是,由于您的后台工作(发送电子邮件)是在 HTTP 请求之外完成的,因此它确实应该在您的 Web 应用程序进程之外完成。一旦你接受了这一点,剩下的解决方案就到位了:

  1. 您需要一个持久的存储队列来完成这项工作。Hangfire 使用您的数据库;我倾向于喜欢 Azure 存储队列等云队列。
  2. 这意味着您需要复制所有需要的数据,因为它需要序列化到该队列中。同样的限制也适用于 Hangfire,只是因为 Hangfire 在同一个 Web 应用程序进程中运行,所以并不明显。
  3. 您需要一个后台进程来执行您的工作队列。我更喜欢 Azure Functions,但另一种常见的方法是将ASP.NET Core Worker 服务作为 Win32 服务或 Linux 守护程序运行。Hangfire 有自己的临时进程内线程。在进程内运行 ASP.NET Core 托管服务也可以,尽管它与 Hangfire 有一些相同的缺点,因为它也在 Web 应用程序进程中运行。
  4. 最后,您的工作队列处理器应用程序有自己的服务注入,如果需要,您可以对其进行编码以创建每个工作队列项的依赖范围。

IMO,这是随着您的 Web 应用程序“成长”而达到的正常阈值。它比简单的 Web 应用程序更复杂:现在您有了一个 Web 应用程序、一个持久队列和一个后台处理器。因此,您的部署变得更加复杂,您需要考虑诸如对工作队列模式进行版本控制这样的事情,这样您就可以在不停机的情况下进行升级(Hangfire 无法很好地处理)等等。一些开发人员对此非常犹豫,因为当“他们想要做的只是发送一封电子邮件而不等待它,但事实是,当一个婴儿网络应用程序被分发时,这是向上的必要步骤。

于 2021-11-16T23:16:15.460 回答