6

我需要任何部署了使用 Sql Server Service Broker 外部激活机制(通过 Feature Pack 中的 Service Broker External Activator)的实际生产应用程序的人的指导。

目前的心态:

我的规格相当简单(或者至少我是这么认为的),所以我正在考虑以下基本流程:

  1. 类似订单的实体被插入到状态为“已确认”的Table_Orders

  2. SP_BeginOrder被执行并执行以下操作:

    • 开始交易
    • 启动一个从Service_HandleOrderStateService_PreprocessOrder的 DIALOG
    • 将对话句柄(从现在开始PreprocessingHandle )存储在Orders表 的特定列中
    • 使用PreprocessingHandle发送包含订单 ID的Message_PreprocessOrder类型的 MESSAGE
    • 结束交易

    请注意,我不会结束对话,我不想“一劳永逸”

  3. Queue_PreprocessOrder上的事件通知激活PreprocessOrder.exe的一个实例(最大并发 1),它执行以下操作:

    • 开始一个 SqlTransaction
    • Queue_PreprocessOrder接收前 1 个 MESSAGE
    • 如果消息类型是Message_PreprocessOrder(格式 XML):
      • 使用消息正文中的订单 ID 在Table_Orders中将订单状态设置为“预处理”
      • 加载计算n 元 Carthesian 积的 n 个数据集合(通过 Linq,AFAIK,这在 T-SQL 中是不可能的)以确定订单项集合
      • 将订单项行插入Table_OrderItems
      • 使用PreprocessingHandle发送Message_PreprocessingDone类型的 MESSAGE ,包含相同的订单 ID
      • 结束与PreprocessingHandle相关的对话
    • 提交 SqlTransaction
    • 以 Environment.Exit(0) 退出
  4. Queue_HandleOrderState上的内部激活执行一个 SP(最大并发 1):
    • 开始交易
    • Queue_InitiatePreprocessOrder接收前 1 个 MESSAGE
    • 如果消息类型是Message_PreprocessingDone
      • 使用消息正文中的订单 ID 在Table_Orders中将订单状态设置为“处理中”
      • 启动从Service_HandleOrderStateService_ProcessOrderItem的 DIALOG
      • 将对话句柄(从现在开始ProcessOrderItemsHandle )存储在Table_Orders的特定列中
      • 为当前订单 ID 和每一行 的Table_OrderItems中的行创建一个游标:
        • 使用ProcessOrderItemsHandle发送Message_ProcessOrderItem类型的 MESSAGE ,其中包含订单项目 ID
    • 如果消息类型是Message_ProcessingDone
      • 使用消息正文中的订单 ID 在Table_Orders中将订单状态设置为“已处理”
    • 如果消息类型是http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog(END DIALOG):
      • 结束与消息的对话句柄有关的对话
    • 结束交易
  5. Queue_ProcessOrderItem上的事件通知激活ProcessOrderItem.exe的一个实例(最大并发 1),它执行以下操作:
    • 开始一个 SqlTransaction
    • Queue_ProcessOrderItem接收前 1 个 MESSAGE
    • 如果消息类型是Message_ProcessOrderItem(格式 XML):
      • 使用消息正文中的订单项目 ID 在 Table_OrdersItems中将订单项目状态设置为“处理中” ,然后:
        • 加载订单项目参数的集合
        • 使用参数向 URL 发出 HttpRequest
        • 将 HttpResponse 作为 PDF 存储在文件系统上
      • 如果上述子步骤中发生任何错误,则将订单项目状态设置为“错误”,否则设置为“正常”
      • 在Table_OrdersItems中执行查找以确定是否所有订单项目都已处理(状态为“ok”或“error”)
      • 如果处理了所有订单项目:
        • 使用ProcessOrderItemsHandle发送Message_ProcessingDone类型的 MESSAGE ,包含订单 ID
        • 结束与ProcessOrderItemsHandle相关的对话
    • 提交 SqlTransaction
    • 以 Environment.Exit(0) 退出

笔记:

  • 规范指定 MSSQL 兼容性 2005 到 2012,因此:
    • 没有对话组
    • 没有对话优先级
    • 没有 POISON_MESSAGE_HANDLING ( STATUS = OFF )
  • 我正在努力实现整体流程的完整性和连续性,而不是速度
  • 鉴于表和 SP 驻留在DB1中,而 Service Broker 对象(消息、合同、队列、服务)驻留在DB2中,DB2是 SET TRUSTWORTHY

问题:

  1. 所描述的架构中是否存在任何重大设计缺陷?
  2. 订单完成状态跟踪似乎不正确。有没有更好的方法?也许使用 QUEUE RETENTION ?
  3. 我的直觉告诉我,在任何情况下,激活的外部 exe 都不应该以 0 以外的退出代码终止,所以应该try{..}catch(Exception e){..} finally{ Environment.Exit(0) }在 Main.exe 中。这个假设正确吗?
  4. 您将如何组织 DB 代码中的错误处理?错误日志表是否足够?
  5. 您将如何组织外部 exe C# 代码中的错误处理?相同的错误记录表?
  6. 我已经看过SQL Server Service Broker Product Samples,但对于我看似简单的案例,Service Broker 接口似乎有点过头了。更简单的 Service Broker 对象模型的任何替代方案?
  7. 任何用于服务代理的跨版本“便携式”管理工具至少能够排出有害消息?
  8. 对于上述任何一个,你有什么像样的代码示例吗?
4

1 回答 1

3

问:所描述的架构中是否存在任何重大设计缺陷?
A: 几个小好处:
- 等待一个 HTTP 请求完成,同时保持一个事务打开是不好的。无论如何,您无法在数据库和 HTTP 之间实现事务一致性,因此当 HTTP 速度较慢时,不要冒险让事务延长几分钟。典型的模式是 {begin tran/receive/ begin conversation timer /commit} 然后发出没有任何 DB xact 的 HTTP 调用。如果 HTTP 调用成功,则 {begin xact/send response/end conversation/commit}。如果 HTTP 失败(或客户端崩溃),那么让会话时间再次激活您。您将收到一条计时器消息(无正文),您需要从表中获取与句柄关联的项目 ID。

问:订单完成状态跟踪似乎不正确。有没有更好的方法?也许使用 QUEUE RETENTION ?
答:我对您的状态跟踪的一个批评是依赖于扫描订单项目以确定当前处理的项目是最后一个(5.3.4)。例如,您可以在项目状态中添加这是要处理的“最后一个”项目的信息,以便在处理它时知道需要报告完成。RETENTION 仅在调试时有用,或者当您有需要运行“逻辑回滚”和补偿对话错误操作的逻辑时。

问:我的直觉告诉我,在任何情况下,激活的外部 exe 都不应该以 0 以外的退出代码终止,所以应该有 try{..}catch(Exception e){..} finally{ Environment.Exit(0 ) } 在主要。这个假设正确吗?
A:最重要的是被激活的进程在队列上发出RECEIVE语句。如果没有这样做,队列监视器可能会永远进入通知状态。如果我没记错的话,退出代码是无关紧要的。与任何后台进程一样,捕获和记录异常都很重要,否则当它开始失败时,您甚至永远不会知道它有问题。除了规范的 try/catch 块之外,HookupApplication.ThreadException还适用于 UI 应用程序以及AppDomain.UnhandledExceptionUI 和非 UI 应用程序。

问:您将如何组织 DB 代码中的错误处理?错误日志表是否足够?
答:我稍后会跟进。错误日志表就足够了。

问:您将如何组织外部 exe C# 代码中的错误处理?相同的错误记录表?
答:我创建bugcollect.com正是因为我必须用自己的应用程序处理此类问题。问题不仅仅是日志记录,您还需要一些聚合和分析(至少检测重复报告)并抑制来自“现场”某些部署配置事故的错误泛滥。说实话,现在有更多的选择,例如。除了网站。当然,我认为 FogBugs 也具有日志记录功能。

问:我已经看过 SQL Server Service Broker 产品示例,但对于我看似简单的案例,Service Broker 接口似乎有点过头了。更简单的 Service Broker 对象模型的任何替代方案?
最后,一个简单的问题:是的,这太过分了。没有简单的模型。

问:是否有任何用于 Service Broker 的跨版本“便携式”管理工具至少能够排出有害消息?
答:毒消息的问题在于毒消息的定义会随您的代码而变化:毒消息是指破坏当前设置的用于检测它的保护措施的任何消息

问:对于上述任何一个,你有什么像样的代码示例吗?
答:没有

还有一点:尽量避免从 DB1 到 DB2 的任何引用(例如,在 DB1 中激活了 4.3.4 并从 DB2 读取项目表)。这会创建跨数据库依赖关系,当 a) 一个数据库脱机(例如,为了维护)或过载或 b) 您为 HA/DR 添加数据库镜像并且一个数据库故障转移时,这些依赖关系会中断。即使 DB1 和 DB2 在不同的机器上(并且没有链接的服务器),也要尝试让代码工作。如有必要,向消息有效负载添加更多信息。如果您以这样的方式构建它,DB2可以在不同的机器上,甚至可以存在多台 DB2 机器来扩展 HTTP/PDF 编写工作。

最后:这个设计会慢。我说的是每秒慢十条消息,涉及很多对话/消息,所有内容都与 max_queue_readers 1 。这对你来说可能接受也可能不接受。

于 2012-11-29T00:17:38.020 回答