Поделиться через


Структура приложения компонента Service Broker

Большинство приложений компонента Service Broker выполняют одни и те же основные действия по получению и обработке сообщений.

  1. Приложение начинает транзакцию.

  2. Если приложение сохраняет сведения о состоянии, оно получает идентификатор группы сообщений. С помощью этого идентификатора приложение восстанавливает состояние из таблицы состояний. Если отсутствует группа сообщений, содержащая сообщения, готовые к получению, то приложение выполняет откат транзакции и завершает работу.

  3. Приложение получает из очереди одно или несколько сообщений. Если приложение обладает идентификатором группы сообщений, то с его помощью оно получает сообщения из этой группы. Когда больше не остается сообщений, доступных для получения, приложение фиксирует транзакцию и возвращается к шагу 1.

  4. Приложение проверяет содержимое сообщений на основании имени типа сообщений.

  5. Приложение обрабатывает содержимое сообщений на основании имени типа сообщений и содержимого сообщения.

  6. Приложение отправляет сообщения, полученные в результате обработки.

  7. Если приложение сохраняет сведения о состоянии, оно обновляет таблицу состояний, используя в качестве первичного ключа для таблицы идентификатор группы сообщений.

  8. Приложение возвращается к шагу 3, чтобы проверить, доступны ли другие сообщения.

Фактическая структура приложения зависит от его требований, стиля передачи данных в приложении, роли приложения (целевая служба или вызывающая служба) и от того, выполняет ли компонент Service Broker активацию этого приложения.

Например, вызывающее приложение отправляет сообщение перед началом цикла обработки, описанного в предыдущих шагах. Вызывающая служба может отправлять сообщение из другой программы или хранимой процедуры, а затем использовать хранимую процедуру активации для запуска очереди обслуживания. Например, в приложение для регистрации заказов может входить внешнее приложение, которое запускает диалог для добавления заказа. После добавления заказа внешнее приложение не должно продолжать работу. Хранимая процедура активации для вызывающей службы отправляет подтверждение запроса, когда служба заказа возвращает ответ. Хранимая процедура активации также обрабатывает все сообщения об ошибках компонента Service Broker, которые возвращаются целевой службой, и отправляет уведомления о том, что не удалось подтвердить заказ.

Вместо отправки сообщения из другой программы вызывающее приложение может отправить сообщение, а затем запустить цикл обработки в пределах одной программы. Независимо от подобных вариантов реализации общая структура приложения остается прежней.

Приложение, которое обрабатывает большое количество сообщений в одной группе сообщений, может вести счетчик полученных сообщений и фиксировать транзакцию после обработки определенного числа сообщений. Такая стратегия подсчета и фиксации позволяет приложению сохранять относительно небольшой размер транзакций и дает возможность обрабатывать различные группы сообщений.

Примеры

В следующем примере кода Transact-SQL обрабатываются все сообщения в очереди MyServiceQueue. Выполняется минимальная обработка сообщений. Если обнаруживается сообщение EndDialog или Error, код завершает диалог. Для любого другого сообщения код создает XML-представление и формирует результирующий набор, который содержит дескриптор диалога, имя типа сообщения и XML-код. Если в течение 500 миллисекунд не доступно ни одного сообщения, код завершает работу.

В целях упрощения сценарий создает результирующий набор для каждого сообщения. Если во время чтения из очереди происходит ошибка, сценарий фиксирует изменения, не формируя результатов. Таким образом сценарий автоматически удаляет сообщения, вызвавшие ошибку.

ПримечаниеПримечание

Поскольку сценарий просто отображает сообщения, для этого сценария невозможно появление опасных сообщений. Поэтому он не содержит код для обработки опасных сообщений. В рабочем приложении необходимо предусмотреть обработку опасных сообщений. Дополнительные сведения об опасных сообщениях см. в разделе Обработка опасных сообщений.

USE AdventureWorks ;
GO

-- Process all conversation groups.

WHILE (1 = 1)
BEGIN

DECLARE @conversation_handle UNIQUEIDENTIFIER,
        @conversation_group_id UNIQUEIDENTIFIER,
        @message_body XML,
        @message_type_name NVARCHAR(128);


-- Begin a transaction, one per conversation group.

BEGIN TRANSACTION ;

-- Get next conversation group.

WAITFOR(
   GET CONVERSATION GROUP @conversation_group_id FROM MyServiceQueue),
   TIMEOUT 500 ;

-- Restore the state for this conversation group here

-- If there are no more conversation groups, break.

IF @conversation_group_id IS NULL
BEGIN
    ROLLBACK TRANSACTION ;
    BREAK ;
END ;

    -- Process all messages in the conversation group.

    WHILE 1 = 1
    BEGIN

        -- Get the next message.

        RECEIVE
           TOP(1)
           @conversation_handle = conversation_handle,
           @message_type_name = message_type_name,
           @message_body =
           CASE
              WHEN validation = 'X' THEN CAST(message_body AS XML)
              ELSE CAST(N'<none/>' AS XML)
          END
       FROM MyServiceQueue
       WHERE conversation_group_id = @conversation_group_id;

       -- If there is no message, or there is an error
       -- reading from the queue, break.

       IF @@ROWCOUNT = 0 OR @@ERROR <> 0
           BREAK;

       -- Process the message. In this case, the program ends the conversation
       -- for Error and EndDialog messages. For all other messages, the program
       -- produces a result set with information about the message.

       SELECT @conversation_handle,
              @message_type_name,
              @message_body ;

       -- If the message is an end dialog message or an error,
       -- end the conversation. Notice that other conversations
       -- in the same conversation group may still have messages
       -- to process. Therefore, the program does not break after
       -- ending the conversation.

       IF @message_type_name =
              'https://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
          OR @message_type_name =
              'https://schemas.microsoft.com/SQL/ServiceBroker/Error'
       BEGIN
          END CONVERSATION @conversation_handle ;
       END ;

    END ; -- Process all messages in conversation group.

   COMMIT TRANSACTION ;

END ; -- Process all conversation groups.