Gerenciamento de Channels


Algum tempo atrás eu falei sobre os internals de um proxy WCF. Como eu havia dito, existe um grande overhead quando criamos um novo proxy, que está condicionado as complexidades que podem ou não estarem habilitadas (segurança, transações, mensagens confiáveis, etc.).

Como disse naquele mesmo post, o ponto mais custoso da criação, que é a factory (ChannelFactory<TChannel>), está sendo reutilizada, em nível de AppDomain, ou seja, mesmo que você não mantenha a instância do proxy gerado (ClientBase<TChannel>) pela IDE do Visual Studio ou pelo utilitário svcutil.exe, o runtime do WCF irá reciclar a factory, e em seguida, a colocará em um cache.

Quando estabelecemos a comunicação entre o cliente e o serviço, utilizamos um canal de comunicação, referido também como channel. Estes são utilizados por nós, na maioria das vezes implicitamente, para efetuar as requisições para o respectivo serviço. Na verdade, é a factory que fornece um método chamado CreateChannel, que retorna a instância de um TransparentProxy. Este tipo nos permite efetuar uma conversão para o contrato exposto pelo documento WSDL, e assim invocar as operações como se elas fossem simples métodos locais. Se você abrir a classe que é gerada quando você faz a referência à um serviço, verá que dentro das operações sempre há uma chamada para a propriedade Channel, que por sua vez, irá até o método CreateChannel.

Como a parte custosa já está sendo reutilizada de forma performática pelo WCF, as vezes surge a dúvida se devemos ou não manter um outro cache, mas este para armazenar as instâncias dos channels que são retornados pelo método CreateChannel, mas que a classe ClientBase<TChannel> não se preocupa com isso. O objeto retornado por esse método implementa a interface ICommunicationObject, que fornece entre vários membros, um método autoexplicativo chamado Close, que é responsável por encerrar mover o estado do proxy corrente para Closed e também descartar os recursos que ele utiliza.

Assim como todo recurso caro, é importante você sempre descartá-lo quando não precisar mais dele. Isso também é o caso dos channels. Mas é importante você analisar cuidadosamente o cenário. Se você faz chamadas subsequentes, não convém a todo momento invocar o método CreateChannel para criar um novo canal; reutilize-o durante essas chamadas, e somente feche-o quando realmente não precisar mais dele, dentro daquele escopo.

Da mesma forma, antes de descartá-lo completamente, analise se você não pode manter um cache para estes channels. Fazer pooling de channels é uma boa alternativa para diminuir ainda mais os custos de criação deles. Você pode manter os channels desde que:

  • Não há um contexto de segurança exclusivo para cada usuário (SCT).
  • O mesmo channel não é utilizado por múltiplas threads ao mesmo tempo.
  • Não há manutenção de estado.

Na primeira situação o problema acontece porque as credenciais são definidas durante a criação da factory, e não podem mais serem alteradas. Já o segundo cenário, acontece porque os channels são thread-safe, ou seja, eles não dão suporte ao envio de mensagem de forma concorrente. Se em uma thread A você está utilizando o channel C1 para mandar uma mensagem grande, a thread B que utilizará o mesmo channel C1, somente conseguirá enviar a mensagem depois que a thread A finalizar. A última das situações implica quando você mantém uma sessão entre o cliente e o serviço, pois ela está fortemente ligada ao channel correspondente.

Anúncios

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s