Мне нужно руководство от любого, кто развернул реальное рабочее приложение, в котором используется механизм внешней активации Sql Server Service Broker (через внешний активатор Service Broker из Feature Pack).
Текущее мышление:
Мои спецификации довольно просты (по крайней мере, я так думаю), поэтому я думаю о следующем основном потоке:
сущность, похожая на заказ, вставляется в Table_Orders со статусом "подтверждено"
SP_BeginOrder выполняется и делает следующее:
- begins a TRANSACTION
- запускает ДИАЛОГ из Service_HandleOrderState в Service_PreprocessOrder
- сохраняет дескриптор диалога (теперь PreprocessingHandle) в определенном столбце таблицы Orders
- отправляет СООБЩЕНИЕ типа Message_PreprocessOrder, содержащее идентификатор заказа, используя PreprocessingHandle
- завершает ТРАНЗАКЦИЮ
Обратите внимание, что я не заканчиваю разговор, я не хочу "выстрелил и забыл"
уведомление о событии в Queue_PreprocessOrder активирует экземпляр PreprocessOrder.exe (максимальное число одновременных действий: 1), который выполняет следующие действия:
- begins a SqlTransaction
- получает первое СООБЩЕНИЕ от 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
- загружает n наборов данных, из которых вычисляется n-арный декартовский продукт (через Linq, AFAIK это невозможно в T-SQL), чтобы определить коллекцию элементов заказа
- вставляет строки элементов заказа в Table_OrderItems
- отправляет СООБЩЕНИЕ типа Message_PreprocessingDone, содержащее тот же идентификатор заказа, используя PreprocessingHandle
- завершает диалог, относящийся к PreprocessingHandle
- фиксирует SqlTransaction
- выходит с Environment.Exit(0)
- internal activation on Queue_HandleOrderState executes a SP (max concurrent of 1) that:
- begins a TRANSACTION
- получает первое СООБЩЕНИЕ от 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
- запускает ДИАЛОГ из Service_HandleOrderState в Service_ProcessOrderItem
- сохраняет дескриптор диалога (теперь ProcessOrderItemsHandle) в определенном столбце 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
- завершает ТРАНЗАКЦИЮ
- event notification on Queue_ProcessOrderItem activates an instance of ProcessOrderItem.exe (max concurrent of 1) which does the following:
- begins a SqlTransaction
- получает первое СООБЩЕНИЕ от 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
- делает HttpRequest к URL-адресу, используя параметры
- сохраняет HttpResponse как PDF в файловой системе
- если на вышеуказанных подшагах возникли какие-либо ошибки, устанавливает состояние элемента заказа в «ошибка», в противном случае «ОК»
- выполняет поиск в Table_OrdersItems, чтобы определить, все ли элементы заказа обработаны (состояние "ok" или "error")
- if all order items are processed:
- sends a MESSAGE of type Message_ProcessingDone, containing the order id, using ProcessOrderItemsHandle
- завершает диалог, относящийся к ProcessOrderItemsHandle
- sets the order item state to "processing" in Table_OrdersItems using the order item id in the message body, then:
- фиксирует SqlTransaction
- выходит с Environment.Exit(0)
Примечания:
- specs specify MSSQL compatibility 2005 through 2012, so:
- no CONVERSATION GROUPS
- нет ПРИОРИТЕТА РАЗГОВОРА
- нет POISON_MESSAGE_HANDLING (STATUS = OFF)
- Я стремлюсь достичь общей целостности и непрерывности потока, а не скорости
- учитывая, что таблицы и SP находятся в DB1, а объекты Service Broker (сообщения, контракты, очереди, службы) находятся в DB2, DB2 УСТАНАВЛИВАЕТСЯ НАДЕЖНЫМ
Вопросы:
- Есть ли в описанной архитектуре какие-либо серьезные конструктивные недостатки?
- Отслеживание состояния выполнения заказа кажется неправильным. Есть ли лучший метод? Может быть, с помощью ОЧЕРЕДИ УДЕРЖАНИЯ?
- Моя интуиция подсказывает мне, что ни в коем случае активированный внешний exe не должен заканчиваться с кодом выхода, отличным от 0, поэтому в Main должно быть
try{..}catch(Exception e){..} finally{ Environment.Exit(0) }
. Верно ли это предположение? - Как бы вы организовали обработку ошибок в коде БД? Достаточно ли таблицы журнала ошибок?
- Как бы вы организовали обработку ошибок во внешнем exe-коде C#? Та же таблица регистрации ошибок?
- Я видел примеры продуктов SQL Server Service Broker, но интерфейс Service Broker кажется излишним для моего, казалось бы, более простого кейс. Есть ли альтернативы более простой объектной модели Service Broker?
- Любой переносной инструмент администрирования для Service Broker с кросс-версией, способный, по крайней мере, сливать ядовитые сообщения?
- Есть ли у вас достойные образцы кода для любого из вышеперечисленного?