I need some guidance from anyone who has deployed a real-world, in-production application that uses the Sql Server Service Broker external activation mechanism (via the Service Broker External Activator from the Feature Pack).
Current mindset:
My specs are rather simple (or at least I think so), so I'm thinking of the following basic flow:
order-like entity gets inserted into a Table_Orders with state "confirmed"
SP_BeginOrder gets executed and does the following:
- begins a TRANSACTION
- starts a DIALOG from Service_HandleOrderState to Service_PreprocessOrder
- stores the conversation handle (from now on PreprocessingHandle) in a specific column of the Orders table
- sends a MESSAGE of type Message_PreprocessOrder containing the order id using PreprocessingHandle
- ends the TRANSACTION
Note that I'm not ending the conversation, I don't want "fire-and-forget"
event notification on Queue_PreprocessOrder activates an instance of PreprocessOrder.exe (max concurrent of 1) which does the following:
- begins a SqlTransaction
- receives top 1 MESSAGE from Queue_PreprocessOrder
- if message type is Message_PreprocessOrder (format XML):
- sets the order state to "preprocessing" in Table_Orders using the order id in the message body
- loads n collections of data of which computes an n-ary Carthesian product (via Linq, AFAIK this is not possible in T-SQL) to determine the order items collection
- inserts the order items rows into a Table_OrderItems
- sends a MESSAGE of type Message_PreprocessingDone, containing the same order id, using PreprocessingHandle
- ends the conversation pertaining to PreprocessingHandle
- commits the SqlTransaction
- exits with Environment.Exit(0)
- internal activation on Queue_HandleOrderState executes a SP (max concurrent of 1) that:
- begins a TRANSACTION
- receives top 1 MESSAGE from Queue_InitiatePreprocessOrder
- if message type is Message_PreprocessingDone:
- sets the order state to "processing" in Table_Orders using the order id in the message body
- starts a DIALOG from Service_HandleOrderState to Service_ProcessOrderItem
- stores the conversation handle (from now on ProcessOrderItemsHandle) in a specific column of Table_Orders
- creates a cursor for rows in Table_OrderItems for current order id and for each row:
- sends a MESSAGE of type Message_ProcessOrderItem, containing the order item id, using ProcessOrderItemsHandle
- if message type is Message_ProcessingDone:
- sets the order state to "processed" in Table_Orders using the order id in the message body
- if message type is
http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog
(END DIALOG):- ends the conversation pertaining to conversation handle of the message
- ends the TRANSACTION
- event notification on Queue_ProcessOrderItem activates an instance of ProcessOrderItem.exe (max concurrent of 1) which does the following:
- begins a SqlTransaction
- receives top 1 MESSAGE from Queue_ProcessOrderItem
- if message type is Message_ProcessOrderItem (format XML):
- sets the order item state to "processing" in Table_OrdersItems using the order item id in the message body, then:
- loads a collection of order item parameters
- makes a HttpRequest to a URL using the parameters
- stores the HttpResponse as a PDF on filesystem
- if any errors occurred in above substeps, sets the order item state to "error", otherwise "ok"
- performs a lookup in the Table_OrdersItems to determine if all order items are processed (state is "ok" or "error")
- if all order items are processed:
- sends a MESSAGE of type Message_ProcessingDone, containing the order id, using ProcessOrderItemsHandle
- ends the conversation pertaining to ProcessOrderItemsHandle
- sets the order item state to "processing" in Table_OrdersItems using the order item id in the message body, then:
- commits the SqlTransaction
- exits with Environment.Exit(0)
Notes:
- specs specify MSSQL compatibility 2005 through 2012, so:
- no CONVERSATION GROUPS
- no CONVERSATION PRIORITY
- no POISON_MESSAGE_HANDLING ( STATUS = OFF )
- I am striving to achieve overall flow integrity and continuity, not speed
- given that tables and SPs reside in DB1 whilst Service Broker objects (messages, contracts, queues, services) reside in DB2, DB2 is SET TRUSTWORTHY
Questions:
- Are there any major design flaws in the described architecture ?
- Order completion state tracking doesn't seem right. Is there a better method ? Maybe using QUEUE RETENTION ?
- My intuition tells me that in no case whatsoever should the activated external exe terminate with an exit code other than 0, so there should be
try{..}catch(Exception e){..} finally{ Environment.Exit(0) }
in Main. Is this assumption correct ? - How would you organize error handling in DB code ? Is an error log table enough?
- How would you organize error handling in external exe C# code ? Same error logging table ?
- I've seen the SQL Server Service Broker Product Samples, but the Service Broker Interface seems overkill for my seemingly simpler case. Any alternatives for a simpler Service Broker object model ?
- Any cross-version "portable" admin tool for Service Broker capable of at least draining poison messages ?
- Have you any decent code samples for any of the above ?