【问题标题】:Microsoft Azure Service Bus Topics Workflow to Save to a Database要保存到数据库的 Microsoft Azure 服务总线主题工作流
【发布时间】:2019-02-12 22:31:49
【问题描述】:

问题

目前,我们的网站已设置为当采取需要发送电子邮件的操作时,我们的网站将调用 SMTP 服务器以尝试发送电子邮件。问题出在 SMTP 服务器出于某种原因出现故障时。我们不会以任何方式存储任何外发电子邮件,因此如果要发送的电子邮件失败,它会永远丢失(不是真的,因为它可以很容易地重新生成,但我们没有机制让我们知道它失败了,除了Azure Application Insights)。虽然我们也让网站在发生异常时向开发人员发送电子邮件,但出于显而易见的原因,我们不会收到这些电子邮件。

目标

我们的目标是停止让我们的网站直接向电子邮件中继服务器发送电子邮件。相反,实施一个可以发送电子邮件并在出现问题时能够恢复的解决方案。

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

解决方案

我读过3-part article,听起来它可以解决这个问题,我目前正在开发它。

我正在使用 Microsoft.Azure.ServiceBus TopicsSubscriptions 构建一个流程来管理从我们的网站发送电子邮件。我经历了很多样本​​,并且已经成功地能够正确地SendAsync()MessageReceiveAsync()MessageCompleteAsync()AbandonAsync()

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

虽然到目前为止大部分流程都已构建,因此我可以了解底层基础架构,但我仍处于规划阶段,以确保我们进行适当的规划。

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

LogTopic 的原因是为了在尝试将日志活动保存到数据库时处理任何暂时性问题。 例如: 我成功检索到要发送的电子邮件。然后我尝试发送电子邮件并记录此尝试。电子邮件已成功发送。然后我尝试记录此活动,但数据库刚刚关闭,我将无法记录此活动。第二个Topic 应该可以缓解这种情况,但如果这种情况下降会怎样?

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

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

在此工作流程中,LogTopic 将包含所有已采取的操作,并在收到消息时存储在数据库中。显然,如果消息因任何原因被放弃并发送DeadLetterQueue,我们将有一个过程在稍后尝试插入它们。

问题

  1. 我们曾考虑在工作流中仅将日志存储到数据库中,但问题是“如果数据库同时出现故障怎么办?” (因此上周 Azure Central US 出现故障时)出现了,所以我们决定使用第二个 Topic。显然,如果Service Bus 已关闭,我们将无法发送此消息,我不知道如何从中恢复,除了记录 ETW 并以其他方式检查它们。我是否应该先尝试进行数据库保存,如果失败,请将Message 发送到Topic
  2. 此服务中发生的事情太多,我是否应该拆分一些操作?
  3. 工作流程本身是否存在我们没有考虑到的缺陷或缺失项?
  4. 我们是否应该使用 1 Topic 并在消息中添加 Label,以便我们知道要发送的是日志还是电子邮件?也许使用过滤器(不确定如何正确执行此操作或是否适合此工作流程)?
  5. 我们是否在这 1 个 SO 帖子中提出了太多问题,是否应该将每个问题分开?

【问题讨论】:

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


    【解决方案1】:

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

    服务总线主题支持单个发送者的多个订阅者。这可以在订阅的帮助下实现。

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

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

    假设创建的订阅是电子邮件和日志。无状态 Service Fabric 服务应侦听来自这两个订阅的消息。

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

    当无状态 Service Fabric 服务收到消息时,它应该启动一个线程来发送邮件。

    成功发送电子邮件后,应向主题发送一条成功消息,其中包含日志订阅的自定义属性。在发送邮件失败的情况下,电子邮件订阅中的消息应该是死信,并且失败消息应该发送到具有适当的日志订阅自定义属性的主题。

    监听来自日志订阅的消息的无状态 Service Fabric 服务将创建一个线程,以便在消息到达时写入数据库。如果写入数据库失败,日志订阅中的消息应该是死信。

    您可以监控两个订阅的死信消息计数,以确保没有失败。如果计数大于0,则需要人工干预Resubmitting dead letter messages to the Topic。市场上可能有一些工具可用于监控和重新提交死信消息,或者您也可以为此开发自定义应用程序。

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

    【讨论】:

    • 谢谢!我肯定会将工作流转换为发送到相同的主题,但使用自定义属性来区分EmailLog。根据您描述的工作流程,听起来我走上了一条好路。当/如果我有其他问题时,我会发布新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    • 2018-10-20
    • 1970-01-01
    • 1970-01-01
    • 2018-11-30
    相关资源
    最近更新 更多