Você já se perguntou como enviar mensagens assíncronas entre limites no SQL Server? Não procure mais do que o SQL Server Service Broker. O Service Broker é uma implementação nativa de filas de mensagens no SQL Server que oferece uma variedade de recursos para facilitar a entrega garantida de mensagens, comunicação assíncrona, API’s públicas, transações e opções de backup.
Então, como o Service Broker funciona? Quando você envia uma mensagem, você especifica uma fila para enviá-la, que pode ser local ou remota. Se a fila estiver offline, a mensagem será mantida em uma loja de transações pendentes e entregue quando a fila voltar online. Existe um serviço receptor que processa as mensagens em ordem da fila e pode enviar uma resposta de volta. O Service Broker garante o processamento em ordem das mensagens e garante a entrega das mensagens, mesmo que elas sejam armazenadas fora de ordem ou processadas em várias threads.
Por que você deve usar o Service Broker? Aqui estão algumas razões:
- Desacoplar dependências de outras aplicações comunicando-se por meio de mensagens.
- Escalar massivamente sua arquitetura movendo filas/processadores de mensagens para servidores separados.
- Desativar/atualizar partes individuais do sistema com impacto mínimo para os usuários finais.
- Controlar como e quando as mensagens são processadas, como enviar mensagens de processamento de pagamento para uma fila para serem processadas durante a noite, durante a carga baixa do servidor.
- Flexibilidade no processamento de filas com vários servidores/processos/threads.
O Service Broker oferece vários benefícios em relação a outras implementações. Ele faz parte do SQL Server, o que significa que ele se integra perfeitamente a outros recursos do SQL Server, como transações, backups, bloqueio de grupos de conversação e espelhamento.
Vamos percorrer um exemplo para ver como o Service Broker pode ser implementado em um cenário do mundo real. Imagine que você está construindo um site de reserva de ingressos com milhares de usuários simultâneos. Dois componentes desse sistema, processamento de pagamento e impressão de ingressos, não precisam acontecer em tempo real e podem ser adiados para períodos de baixa atividade. Veja como funciona:
- Um usuário cria uma reserva clicando no botão “Criar Reserva” no site.
- O servidor web insere o registro da reserva no banco de dados do SQL Server.
- O servidor web envia uma mensagem para a fila de destino do processador de pagamento para processar o pagamento para aquela reserva.
- O serviço de processamento de pagamento pega a mensagem e processa o pagamento.
- Se o pagamento for bem-sucedido, ele envia uma mensagem de sucesso de pagamento de volta para a fila de origem do processador de pagamento. Se falhar, ele envia uma mensagem de falha de volta.
- O SQL Server monitora a fila de origem do iniciador de pagamento para respostas de pagamento. Se um pagamento falhar, ele define o registro da reserva como pagamento falhou. Se o pagamento for bem-sucedido, ele define a tabela de reservas como pagamento bem-sucedido e envia uma mensagem para a fila de destino da impressora de ingressos.
- O serviço de impressão de ingressos pega a mensagem na fila de destino da impressora de ingressos e imprime o ingresso. Se for bem-sucedido, ele envia uma mensagem de sucesso de volta para a fila de origem da impressora de ingressos. Se falhar, ele envia uma mensagem de falha.
- O SQL Server pega a mensagem na fila de origem da impressora de ingressos e define o ingresso como impresso ou falhou.
Com o Service Broker, é fácil adicionar servidores de processamento de pagamento/impressão conforme necessário e agendá-los para iniciar e parar com base na disponibilidade de recursos. Isso seria muito mais difícil de implementar de forma síncrona no seu servidor web/SQL Server.
Vamos dar uma olhada em alguns exemplos de código para entender como implementar o Service Broker. Primeiro, precisamos definir nossos tipos de mensagem:
CREATE MESSAGE TYPE [PrintRequest] VALIDATION = WELL_FORMED_XML
CREATE MESSAGE TYPE [PrintResponse] VALIDATION = WELL_FORMED_XML
CREATE MESSAGE TYPE [ProcessPaymentRequest] VALIDATION = WELL_FORMED_XML
CREATE MESSAGE TYPE [ProcessPaymentResponse] VALIDATION = WELL_FORMED_XML
Em seguida, definimos as filas para as mensagens:
CREATE QUEUE PrintInitiatorQueue WITH ACTIVATION (STATUS = ON, PROCEDURE_NAME = [BrokerPrintMessageProcessed], MAX_QUEUE_READERS = 4, EXECUTE AS SELF)
CREATE QUEUE PrintTargetQueue WITH STATUS = ON
CREATE QUEUE ProcessPaymentInitiatorQueue WITH ACTIVATION (STATUS = ON, PROCEDURE_NAME = [BrokerPaymentMessageProcessed], MAX_QUEUE_READERS = 4, EXECUTE AS SELF)
CREATE QUEUE ProcessPaymentTargetQueue WITH STATUS = ON
Também precisamos criar contratos para definir as mensagens permitidas em uma conversa:
CREATE CONTRACT [ProcessPaymentContract] ([ProcessPaymentResponse] SENT BY TARGET, [ProcessPaymentRequest] SENT BY INITIATOR)
CREATE CONTRACT [PrintContract] ([PrintRequest] SENT BY INITIATOR, [PrintResponse] SENT BY TARGET)
Por fim, criamos os serviços:
CREATE SERVICE PrintInitiatorService ON QUEUE PrintInitiatorQueue (PrintContract)
CREATE SERVICE PrintTargetService ON QUEUE PrintTargetQueue (PrintContract)
CREATE SERVICE ProcessPaymentInitiatorService ON QUEUE ProcessPaymentInitiatorQueue (ProcessPaymentContract)
CREATE SERVICE ProcessPaymentTargetService ON QUEUE ProcessPaymentTargetQueue (ProcessPaymentContract)
Agora que temos tudo configurado, podemos começar a enviar mensagens de ida e volta. Por exemplo, quando um usuário cria uma reserva, podemos chamar um procedimento armazenado que insere o registro da reserva e envia uma mensagem para a fila ProcessPaymentTarget para processamento de pagamento:
CREATE PROCEDURE [dbo].[CreateBooking] (@EventId INT, @CreditCard VARCHAR(20))
AS
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Bookings (EventId, CreditCard) VALUES (@EventId, @CreditCard)
DECLARE @BookingId INT = SCOPE_IDENTITY()
-- Enviar mensagem para processamento de pagamento
DECLARE @ConversationHandle UNIQUEIDENTIFIER
BEGIN DIALOG CONVERSATION @ConversationHandle
FROM SERVICE [ProcessPaymentInitiatorService]
TO SERVICE 'ProcessPaymentTargetService'
ON CONTRACT [ProcessPaymentContract]
WITH ENCRYPTION = OFF
DECLARE @Msg NVARCHAR(MAX)
SET @Msg = '' + CAST(@BookingId AS NVARCHAR(10)) + ' ' + @CreditCard + ' ';
SEND ON CONVERSATION @ConversationHandle MESSAGE TYPE [ProcessPaymentRequest] (@Msg)
COMMIT
END TRY
BEGIN CATCH
RAISERROR('Falha na reserva', 1, 1)
ROLLBACK
RETURN
END CATCH
Neste exemplo, especificamos os serviços de origem e destino, juntamente com o contrato a ser usado e enviamos a mensagem. O projeto completo de exemplo no GitHub fornece mais detalhes sobre como lidar com as mensagens recebidas e processá-las adequadamente.
O Service Broker oferece uma maneira poderosa e flexível de implementar filas de mensagens no SQL Server. Ele permite que você desacople dependências, escale sua arquitetura e controle como e quando as mensagens são processadas. Com sua integração perfeita com os recursos do SQL Server, o Service Broker é uma escolha confiável para implementar filas de mensagens em suas aplicações do SQL Server.