Sql Server Service Broker - 外部激活的控制台应用程序的全面,正在使用的示例

Ste*_*hel 5 sql-server activation sample service-broker

我需要部署使用Sql Server Service Broker外部激活机制(通过Feature Pack中的Service Broker外部激活器)的现实生产应用程序的任何人的一些指导.

目前的心态:

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

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

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

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

    请注意,我不是在结束谈话,我不想要"永远不要忘记"

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

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

笔记:

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

问题:

  1. 所描述的架构中是否存在任何重大设计缺陷?
  2. 订单完成状态跟踪似乎不对.有更好的方法吗?也许使用QUEUE RETENTION?
  3. 我的直觉告诉我,在任何情况下,激活的外部exe都不会try{..}catch(Exception e){..} finally{ Environment.Exit(0) }以0以外的退出代码终止,因此应该在Main中.这个假设是否正确?
  4. 您将如何组织数据库代码中的错误处理?错误日志表是否足够?
  5. 您将如何组织外部exe C#代码中的错误处理?相同的错误记录表?
  6. 我见过SQL Server Service Broker产品样本,但Service Broker界面对于我看似简单的案例来说似乎有些过分.更简单的Service Broker对象模型的任何替代方案?
  7. Service Broker的任何跨版本"便携式"管理工具至少能够排出有害消息?
  8. 您有任何上述代码样本吗?

Rem*_*anu 3

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

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

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

问:您将如何组织数据库代码中的错误处理?错误日志表就足够了吗?
答:我稍后会跟进此事。恕我直言,错误日志表就足够了。

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

问:我已经看过 SQL Server Service Broker 产品示例,但 Service Broker 界面对于我看似简单的案例来说似乎有些过分了。是否有更简单的 Service Broker 对象模型的替代方案?
最后,一个简单的问题:是的,这太过分了。没有简单的模型。

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

问:您有上述任何一个合适的代码示例吗?
答:没有

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

最后:这个设计会非常慢。我说的是每秒低数十条消息,速度很慢,涉及如此多的对话框/消息,并且所有内容都与 max_queue_readers 1 相关。这对您来说可能可以接受,也可能不可接受。