Microsoft Azure服务总线主题工作流以保存到数据库

时间:2018-09-07 14:34:55

标签: c# azure azure-service-fabric azureservicebus

问题

当前,我们的网站已设置好,以便在采取措施要求发送电子邮件时,我们的网站将呼叫SMTP服务器以尝试发送电子邮件。问题出在SMTP服务器由于任何原因而关闭时。我们不会以任何方式存储任何传出的电子邮件,因此,如果要发送的电子邮件失败了,它将永远丢失(并不是因为可以轻松地重新生成它,但是我们没有机制让我们知道它失败了,除了Azure Application Insights)。虽然我们也有网站在异常发生时向开发人员发送电子邮件,但出于明显的原因,我们不会收到这些电子邮件。

目标

我们的目标是停止让我们的网站直接将电子邮件发送到电子邮件中继服务器。取而代之的是,实施一种解决方案,该解决方案可以发送电子邮件并能够在出现问题时进行恢复。

  1. 停止发送电子邮件的网站
  2. 能够从暂时或附带问题/异常中恢复
  3. 尽可能记录有关电子邮件的活动(发送尝试/失败/等)
  4. 能够从潜在的临时或附带问题/异常中恢复活动日志
  5. 如有必要,可以重新触发要发送的电子邮件(可选)

解决方案

我读了一个3-part article,听起来好像可以解决此问题,并且我正在开发它。

我正在使用Microsoft.Azure.ServiceBus TopicsSubscriptions构建一个流程来管理从我们的网站发送电子邮件。我经历了许多示例,并成功地SendAsync()MessageReceiveAsync()Message适当地。

旁注:我现在正在探索如何与RetryPolicy一起使用,以查看这是否有助于将重试时间推迟更长的时间,尽管我我不确定是否可以/应该使用它。

尽管到目前为止,大多数流程都已构建,因此我可以理解底层基础结构,但我仍处于计划阶段,以确保我们进行适当的计划。

我们目前正在尝试为此流程找到最佳或最合适的工作流程。我们认为需要两个CompleteAsync():一个用于发送电子邮件 EmailTopic ,另一个用于记录 LogTopic 的日志。

使用AbandonAsync()的原因是要在尝试将日志活动保存到数据库时处理所有暂时性问题。 例如:我成功检索了要发送的电子邮件。然后,我尝试发送电子邮件并记录此尝试。电子邮件已成功发送。然后,我尝试记录该活动,但是数据库刚刚关闭,我将无法记录此活动。第二个Topics应该可以缓解这种情况,但是如果出现这种情况怎么办?

这是我们当前的工作流程:

  1. 网站将数据插入到定义要发送的电子邮件的数据库中(当前,我们将有LogTopic的字段,该字段将是电子邮件内容本身,另一个用于保存Topic的表其中将包含Body字段周围的内容,以及从,到,CC,BCC和文件附件)
  2. 网站将带有插入记录的Email Templates的小Body发送到Message
  3. 一个EmailTopic监听消息
  4. 接收MessageId,从数据库中获取记录的所有详细信息
  5. 构建Stateless Service Fabric Service并尝试将电子邮件发送到SMTP服务器
  6. Message发送SMTPClient,并附带Message,当前日期,当前LogTopic和已采取的措施(尝试发送电子邮件)
    • 如果成功,则MessageId DeliveryCount并将CompleteAsync(),当前日期,当前Message发送到MessageLogTopic,并采取的措施:“发送电子邮件”
    • 如果未成功,请MessageId DeliveryCount并将AbandonAsync(),当前日期,当前Message发送到Message的{​​{1}},并采取的措施:“电子邮件发送失败”(尝试10次后,邮件将自动放入LogTopic

在此工作流程中,MessageId将包含所有已执行的操作,并在收到消息时存储在数据库中。显然,如果由于任何原因放弃了邮件并发送了DeliveryCount,我们将有一个尝试在以后插入它们的过程。

问题

  1. 我们考虑过只将日志存储到工作流中的数据库中,但是问题是:“如果数据库在此期间关闭,那又会是什么?” (因此,上周美国中部Azure出现故障)因此我们决定使用第二个DeadLetterQueue。显然,如果LogTopic处于关闭状态,我们将无法发送此消息,而且我不知道如何从中恢复,除了登录ETW并以其他方式检查它们。我是否应该先尝试进行数据库保存,如果失败,将DeadLetterQueue发送到Topic
  2. 此服务中发生的事情太多了吗,我应该拆分一些操作吗?
  3. 工作流本身是否存在我们没有考虑的缺陷或缺失?
  4. 我们应该使用1 Service Bus并在邮件中添加Message以便我们知道它是要发送的日志还是电子邮件?也许使用过滤器(不确定如何正确执行此操作,或者尚不适合此工作流程)?
  5. 我们在1个SO帖子中问的问题太多了吗,应该将每个问题分开吗?

1 个答案:

答案 0 :(得分:2)

我认为可以以跟踪和解决故障的方式改进工作流程。我正在为实现这一目标提供解决方案。

服务总线主题支持单个发件人的多个订户。这可以通过订阅实现。

您可以在一个主题下创建两个订阅,而不是将消息发送到两个主题。请参阅here,以使用规则将邮件过滤到“订阅”中。

您可以为订阅创建不同的规则。将消息发送到主题后,将根据每个订阅的规则验证消息的自定义属性。根据验证的结果,消息将进入具有所需规则条件的订阅。

可以说创建的订阅是电子邮件和日志。无状态服务结构服务应侦听来自这两个订阅的消息。

网站应使用“电子邮件订阅”的自定义属性将消息发送到主题。

每当Stateless Service Fabric服务接收到一条消息时,它都应该启动一个线程来发送邮件。

成功发送电子邮件后,应将成功消息发送到带有“日志订阅”的自定义属性的主题。如果发送邮件失败,则“电子邮件订阅”中的消息应标有死信,并且应将“失败”消息发送给具有“日志订阅”的适当自定义属性的主题。

无状态服务结构服务(还会监听来自日志订阅的消息)将创建一个线程,以在消息到达时写入数据库。如果无法写入数据库,则“日志订阅”中的消息应标有死信。

您可以监视两个订阅的死信消息计数,以确保没有失败。如果计数大于0,则应手动干预将死信消息重新提交给主题。市场上可能有监视或重新发送死信消息的工具,或者您也可以开发一个自定义应用程序来做到这一点。

我想这个工作流程应该可以正常工作。安装完成后,唯一需要注意的是两个订阅中的死信消息。