Esta página foi útil?
Seus comentários sobre este conteúdo são importantes. Queremos saber sua opinião.
Comentários adicionais?
1500 caracteres restantes
Exportar (0) Imprimir
Expandir Tudo

Criando aplicativos que usam filas do Barramento do Serviço

Atualizado: março de 2015

Este artigo descreve a utilidade das filas e mostra como criar um aplicativo simples baseado em fila que usa o Barramento do Serviço do Microsoft Azure.

Vamos considerar um cenário do mundo de varejo em que os dados de vendas dos terminais de Ponto de Venda (PDV) individuais devem ser roteados para um sistema de gerenciamento de estoque que usa esses dados para determinar quando deve ocorrer a reposição do estoque. A solução a seguir usa o sistema de mensagens do Barramento do Serviço para a comunicação entre os terminais e o sistema de gerenciamento de estoque, conforme ilustrado abaixo:

Service-Bus-Queues-Img1

Cada terminal de PVD reporta seus dados de vendas enviando mensagens para a DataCollectionQueue. Essas mensagens permanecem nessa fila até serem recuperadas pelo sistema de gerenciamento de estoque. Esse padrão é geralmente denominado sistema de mensagens assíncronas porque o terminal de PDV não precisa esperar uma resposta do sistema de gerenciamento de estoque para continuar o processamento.

Antes de examinarmos o código necessário para configurar esse aplicativo, considere as vantagens de usar uma fila nesse cenário, em vez de fazer com que os terminais de PDV se comuniquem diretamente (de forma síncrona) com o sistema de gerenciamento de estoque.

Com o padrão de mensagens síncronas, os produtores e os consumidores não precisam estar online ao mesmo tempo. A infraestrutura de mensagens armazena de forma confiável as mensagens até que a parte consumidora esteja pronta para recebê-las. Isso permite que os componentes do aplicativo distribuído sejam desconectados voluntariamente, por exemplo, para manutenção, ou devido a uma falha do componente, sem afetar o sistema inteiro. Além disso, é possível que o aplicativo de consumo precise estar online somente durante determinadas horas do dia. Por exemplo, nesse cenário de varejo, o sistema de gerenciamento de estoque talvez só precise ficar online após o final do dia útil.

Em vários aplicativos, a carga do sistema varia ao longo do tempo, enquanto o tempo de processamento necessário para cada unidade de trabalho é normalmente constante. A intermediação dos produtores e dos consumidores de mensagens com uma fila significa que o aplicativo de consumo (o processo de trabalho) só precisa ser provisionado para atender a uma carga média, em vez de uma carga de pico. O tamanho da fila aumentará e diminuirá à medida que a carga de entrada variar. Isso resulta em uma economia do custo relacionado ao tamanho da infraestrutura necessária para atender à carga do aplicativo.

Service-Bus-Queues-Img2

À medida que a carga aumenta, mais processos de trabalho podem ser adicionados para realizar operações de leitura na fila de trabalho. Cada mensagem é processada por apenas um dos processos de trabalho. Além disso, esse balanceamento de carga baseado em pull permite o uso otimizado dos computadores de trabalho mesmo que esses computadores tenham capacidades de processamento diferentes, uma vez que eles efetuarão pull das mensagens em sua própria velocidade máxima. Esse padrão é geralmente denominado de consumidor concorrente.

Service-Bus-Queues-Img3

O uso de filas de mensagens para intermediar os produtores e os consumidores de mensagens fornece um acoplamento flexível intrínseco entre os componentes. Como os produtores e os consumidores não têm conhecimento uns dos outros, um consumidor poderá ser atualizado sem causar qualquer impacto ao produtor. Além disso, a topologia de mensagens poderá evoluir sem afetar os pontos de extremidade existentes. Discutiremos isso em mais detalhes quando falarmos sobre publicação/assinatura.

A seção a seguir mostra como usar o Barramento do Serviço para criar esse aplicativo.

Você precisará de uma conta Azure para começar a trabalhar com o Barramento do Serviço. Caso ainda não tenha uma conta, você poderá inscrever-se para obter uma avaliação gratuita aqui. Você precisará se conectar com uma Windows Live ID (conta da Microsoft)., que será associada à sua conta do Barramento do Serviço. Depois de fazer isso, você poderá criar uma nova assinatura do Barramento do Serviço. No futuro, toda vez que fizer logon com a sua Windows Live ID (conta da Microsoft)., você terá acesso a todas as assinaturas do Barramento do Serviço associadas à sua conta.

Quando tiver uma assinatura, você poderá criar um novo namespace de serviço. Você precisará atribuir um nome exclusivo ao seu novo namespace de serviço em todas as contas do Barramento do Serviço. Cada namespace de serviço funciona como um contêiner para um conjunto de entidades do Barramento do Serviço. Para obter mais informações, consulte Como: Criar ou modificar um namespace do serviço do Service Bus.

Para usar o Barramento do Serviço namespace de serviço, um aplicativo deverá fazer referência ao assembly do Barramento do Serviço, especificamente o Microsoft.ServiceBus.dll. Você poderá encontrar esse assembly como parte do SDK do Microsoft Azure, que está disponível para download na página de download do SDK do Azure. Entretanto, o pacote NuGet do Barramento do Serviço é a maneira mais fácil de obter a API do Barramento do Serviço e configurar seu aplicativo com todas as dependências do Barramento do Serviço. Para obter detalhes sobre o uso do NuGet e do pacote do Barramento do Serviço, consulte Usando o pacote NuGet do Barramento do Serviço.

As operações de gerenciamento das entidades de mensagens do Barramento do Serviço (filas e tópicos de publicação/assinatura) são executadas por meio da classe NamespaceManager. O Barramento do Serviço usa um modelo de segurança baseado em declarações implementado com o uso do Access Control do Active Directory do Microsoft Azure (também conhecido como Access Control Service ou ACS). São necessárias credenciais apropriadas para criar uma instância NamespaceManager para determinado namespace de serviço. A classe TokenProvider representa um provedor de token de segurança com métodos de fábrica de incorporados que retornam alguns provedores de token bem conhecidos. Vamos usar um método CreateSharedAccessSignatureTokenProvider para manter o acesso compartilhado às credenciais de assinatura (SAS). Em seguida, a instância NamespaceManager é construída com o endereço básico do Barramento do Serviço namespace de serviço e do provedor de token.

A classe NamespaceManager fornece métodos para criar, enumerar e excluir entidades de mensagens. O trecho de código ilustrado aqui mostra como a instância NamespaceManager é criada e usada para criar a fila DataCollectionQueue.

Uri uri = ServiceBusEnvironment.CreateServiceUri("sb""ingham-blog"string.Empty);
string name = "RootManageSharedAccessKey";
string key = "abcdefghijklmopqrstuvwxyz";
 
TokenProvider tokenProvider = 
    TokenProvider.CreateSharedAccessSignatureTokenProvider(name, key);
NamespaceManager namespaceManager = 
    new NamespaceManager(uri, tokenProvider);
namespaceManager.CreateQueue("DataCollectionQueue");

Observe que há sobrecargas do método CreateQueue que permitem ajustar as propriedades da fila. Por exemplo, você pode definir o valor TTL (vida útil) padrão das mensagens enviadas para a fila.

Para operações em tempo de execução nas entidades do Barramento do Serviço; por exemplo, ao enviar e receber mensagens, o aplicativo precisa primeiro criar um objeto MessagingFactory. De maneira semelhante à classe NamespaceManager, a instância MessagingFactory é criada a partir do endereço básico do namespace de serviço e do provedor de token.

 MessagingFactory factory = MessagingFactory.Create(uri, tokenProvider);

As mensagens enviadas para as filas do Barramento do Serviço e recebidas dessas filas são instâncias da classe BrokeredMessage. Essa classe consiste em um conjunto de propriedades padrão (como Label e TimeToLive), um dicionário que é usado para armazenar as propriedades do aplicativo e um corpo de dados arbitrários do aplicativo. O aplicativo poderá definir o corpo passando qualquer objeto serializável (o exemplo a seguir passa um objeto SalesData que representa os dados de vendas do terminal de PDV), que usará o DataContractSerializer para serializar o objeto. Opcionalmente, um Stream poderá ser fornecido.

 BrokeredMessage bm = new BrokeredMessage(salesData);
 bm.Label = "SalesReport";
 bm.Properties["StoreName"] = "Redmond";
 bm.Properties["MachineID"] = "POS_1";

A maneira mais simples de enviar mensagens para determinada fila, em nosso caso a fila DataCollectionQueue, é usar CreateMessageSender para criar um objeto MessageSender diretamente a partir da instância MessagingFactory.

MessageSender sender = factory.CreateMessageSender("DataCollectionQueue");
sender.Send(bm);

A maneira mais fácil de receber mensagens da fila é usar um objeto MessageReceiver que pode ser criado diretamente a partir da instância MessagingFactory usando CreateMessageReceiver. Os receptores das mensagens podem funcionar de dois modos diferentes: ReceiveAndDelete e PeekLock. O ReceiveMode é definido quando o receptor das mensagens é criado, como um parâmetro para a chamada de CreateMessageReceiver.

Ao usar o modo ReceiveAndDelete, o recebimento é uma operação de uma única etapa; ou seja, quando o Barramento do Serviço recebe a solicitação, ele marca a mensagem como sendo consumida e retorna-a para o aplicativo. O modo ReceiveAndDelete é o modelo mais simples e funciona melhor nos cenários em que o aplicativo é capaz de tolerar o não processamento de uma mensagem em caso de uma falha. Para entender isso, considere um cenário em que o consumidor emite a solicitação de recebimento e falha antes de processá-la. Como o Barramento do Serviço marcou a mensagem como sendo consumida, quando o aplicativo é reiniciado e começa a consumir as mensagens novamente, ele terá perdido a mensagem consumida antes da falha.

No modo PeekLock, o recebimento torna-se uma operação de duas etapas, possibilitando o suporte de aplicativos que não podem tolerar mensagens ausentes. Quando o Barramento do Serviço recebe a solicitação, ele encontra a próxima mensagem a ser consumida, boqueia-a para impedir que outros consumidores a recebam e retorna-a para o aplicativo. Quando o aplicativo termina de processar a mensagem (ou a armazena com segurança para processamento futuro), ele conclui a segunda etapa do processo de recebimento chamando Complete na mensagem recebida. Quando o Barramento do Serviço vir Complete, ele marcará a mensagem como sendo consumida.

Dois outros resultados são possíveis. Primeiro, se o aplicativo não for capaz de processar a mensagem por algum motivo, ele chamará Abandon na mensagem recebida (em vez de Complete). Isso fará com que o Barramento do Serviço desbloqueie a mensagem e disponibilize-a para ser recebida novamente, seja pelo mesmo consumidor ou por outro consumidor que tenha concluído o processo. Segundo, há um tempo limite associado ao bloqueio e, se o aplicativo não puder processar a mensagem antes desse tempo limite expirar (por exemplo, se o aplicativo falhar), o Barramento do Serviço desbloqueará a mensagem e a disponibilizará para ser recebida novamente.

Observe que, se o aplicativo falhar após processar a mensagem, mas antes de a solicitação Complete ser emitida, a mensagem será entregue novamente ao aplicativo quando ele reiniciar. Isso é geralmente denominado processamento Pelo Menos Uma Vez. Isso significa que cada mensagem será processada pelo menos uma vez, mas, em certas situações, a mesma mensagem poderá ser entregue novamente. Se o cenário não puder tolerar o processamento duplicado, uma lógica adicional será necessária no aplicativo para detectar as duplicatas. Isso poderá ser alcançado com base na propriedade MessageId da mensagem. O valor dessa propriedade permanece constante durante as tentativas de entrega. Isso é denominado processamento Exatamente Uma Vez.

O código mostrado aqui ilustra como receber e processar uma mensagem usando o modo PeekLock, que será o padrão se nenhum valor de ReceiveMode for fornecido explicitamente.

MessageReceiver receiver = factory.CreateMessageReceiver("DataCollectionQueue");
BrokeredMessage receivedMessage = receiver.Receive();
try
{
    ProcessMessage(receivedMessage);
    receivedMessage.Complete();
}
catch (Exception e)
{
    receivedMessage.Abandon();
}

Nos exemplos anteriores desta seção, criamos os objetos MessageSender e MessageReceiver diretamente a partir de MessagingFactory para enviar e receber mensagens da fila, respectivamente. Uma abordagem alternativa é usar a classe QueueClient, que oferece suporte a operações de envio e recebimento, além de recursos mais avançados, como sessões.

QueueClient queueClient = 
     factory.CreateQueueClient("DataCollectionQueue");
queueClient.Send(bm);
            
BrokeredMessage message = queueClient.Receive();
try
{
    ProcessMessage(message);
    message.Complete();
}
catch (Exception e)
{
    message.Abandon();
} 

Mostrar:
© 2015 Microsoft