Pergunta

Eu criei um serviço WCF e estou utilizando a ligação netMsmqBinding.

Este é um serviço simples que passa um Dto para o meu método de serviço e não espera resposta.A mensagem é colocada em um MSMQ e, uma vez coletada, inserida em um banco de dados.

Qual é o melhor método para garantir que nenhum dado seja perdido.

Eu tentei os 2 métodos a seguir:

  1. Lançar uma exceção

    Isso coloca a mensagem em uma fila de mensagens não entregues para leitura manual.Posso processar isso quando meu strvice começar

  2. defina o receiverRetryCount="3" na ligação

    Após 3 tentativas - que acontecem instantaneamente, isso parece deixar a mensagem na fila, mas falha no meu serviço.Reiniciar meu serviço repete esse processo.

Idealmente, eu gostaria de fazer o seguinte:

Tente processar a mensagem

  • Se isso falhar, aguarde 5 minutos pela mensagem e tente novamente.
  • Se esse processo falhar 3 vezes, mova a mensagem para uma fila de mensagens não entregues.
  • Reiniciar o serviço enviará todas as mensagens da fila de mensagens não entregues de volta para a fila para que possam ser processadas.

Posso conseguir isso?Se sim, como?Você pode me indicar algum bom artigo sobre a melhor forma de utilizar o WCF e o MSMQ para meu cenário específico.

Qualquer ajuda seria muito apreciada.Obrigado!

Algumas informações adicionais

Estou usando o MSMQ 3.0 no Windows XP e no Windows Server 2003.Infelizmente, não posso usar o suporte integrado a mensagens suspeitas direcionado ao MSMQ 4.0 e Vista/2008.

Foi útil?

Solução

Há uma amostra no SDK que pode ser útil no seu caso. Basicamente, o que ele faz é anexar uma implementação IErrorHandler ao seu serviço que vai pegar o erro quando WCF declara a mensagem a ser "veneno" (ou seja, quando todas as tentativas configuradas foram esgotados). O que a amostra não é mover a mensagem para outra fila e, em seguida, reiniciar o ServiceHost associado com a mensagem (uma vez que terá em falha quando a mensagem veneno foi encontrado).

Não é uma amostra muito bonita, mas pode ser útil. Há um par de limitações, no entanto:

1- Se você tem vários pontos de extremidade associados ao seu serviço (isto é exposta através de várias filas), não há nenhuma maneira de saber qual a fila a mensagem veneno chegou. Se você só tem uma única fila, isso não será um problema . Eu não vi nenhuma solução oficial para este, mas eu tenho experimentado com uma possível alternativa que eu tenho documentado aqui: http://winterdom.com/weblog/2008/05/27/NetMSMQAndPoisonMessages.aspx

2 Uma vez que a mensagem de problema é movido para outra fila, torna-se sua responsabilidade, por isso é até você para movê-lo de volta para a fila de processamento uma vez que o tempo de espera é feito (ou anexar um novo serviço para essa fila de lidar com isso ).

Para ser honesto, em ambos os casos, você está olhando para algum trabalho "manual" aqui que WCF apenas não cobre, por si própria.

Eu estive recentemente trabalhando em um projeto diferente, onde eu tenho a obrigação de controlar explicitamente quantas vezes tentativas acontecer, e minha solução atual foi a de criar um conjunto de filas de repetição e manualmente mover mensagens entre as filas de repetição e o processamento principal fila com base em um conjunto de temporizadores e algumas heurísticas, apenas usando o material System.Messaging cru para lidar com as filas MSMQ. Parece funcionar muito bem, embora há um par de truques se você seguir esse caminho.

Outras dicas

Eu acho que com MSMQ (disponíveis apenas no Vista), você pode ser capaz de fazer assim:

<bindings>
    <netMsmqBinding>
        <binding name="PosionMessageHandling"
             receiveRetryCount="3"
             retryCycleDelay="00:05:00"
             maxRetryCycles="3"
             receiveErrorHandling="Move" />
    </netMsmqBinding>
</bindings>

WCF tentará imediatamente para tempos ReceiveRetryCount após a primeira falha chamada. Após o lote falhou a mensagem é movida para a fila de repetição. Depois de um atraso de RetryCycleDelay minutos, a mensagem movido a partir da fila de repetição para a fila de terminais e o lote é repetida. Isto será repetido tempo MaxRetryCycle. Se tudo isso falhar a mensagem é tratada de acordo com ReceiveErrorHandling que pode ser jogada (A fila de veneno), rejeitar, gota ou falha

Pela maneira um bom texto sobre WCF e MSMQ é o chapther 9 de Progammig WCF livro de Juval Lowy

Se você estiver usando SQL-Server, em seguida, você deve usar uma transação distribuída, uma vez que ambos MSMQ e suporte SQL Server-lo. O que acontece é que você enrole a gravação de banco de dados em um bloco de TransactionScope e chamar scope.Complete () somente se for bem sucedido. Se ele falhar, então quando seu método WCF retorna a mensagem será colocada de volta na fila para ser julgado novamente. Aqui está uma versão aparada do uso de código I:

    [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)]
    public void InsertRecord(RecordType record)
    {
        try
        {
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
            {
                SqlConnection InsertConnection = new SqlConnection(ConnectionString);
                InsertConnection.Open();

                // Insert statements go here

                InsertConnection.Close();

                // Vote to commit the transaction if there were no failures
                scope.Complete();
            }
        }
        catch (Exception ex)
        {
            logger.WarnException(string.Format("Distributed transaction failure for {0}", 
                Transaction.Current.TransactionInformation.DistributedIdentifier.ToString()),
                ex);
        }
     }

Eu testar isso na fila um número grande, mas conhecida de registros, vamos WCF começar lotes de tópicos para lidar com muitos deles simultaneamente (alcances 16 tópicos - 16 mensagens fora da fila de uma vez), em seguida, matar o processo no meio de operações. Quando o programa for reiniciado as mensagens são lidas para trás da fila e processadas novamente como se nada tivesse acontecido, e no final do teste o banco de dados é consistente e não tem registros ausentes.

O Distributed Transaction Manager tem uma presença ambiente, e quando você cria uma nova instância de TransactionScope ele procura automaticamente a transação corrente no âmbito da invocação método - que deveria ter sido já criado por WCF quando apareceu a mensagem fora da fila e invocou o seu método.

Infelizmente eu estou preso no Windows XP e Windows Server 2003 para que não é uma opção para mim. - (I vai voltar a esclarecer que na minha pergunta como eu encontrei esta solução após a postagem e percebi que não poderia usá-lo)

Eu achei que uma solução foi a instalação de um manipulador personalizado que iria passar a minha mensagem para outra fila fila ou veneno e reiniciar o serviço. Este parecia loucura para mim. Imagine o meu SQL Server foi para baixo quantas vezes o serviço seria reiniciado.

Então o que eu acabei fazendo é permitir que a linha de falhas e deixar mensagens na fila. Eu também registrar uma mensagem fatal para o meu serviço de log do sistema que isso tenha acontecido. Uma vez que o nosso problema é resolvido, eu reiniciar o serviço e todas as mensagens começam a ser processado novamente.

Eu percebi re-processar esta mensagem ou qualquer outro tudo vai falhar, então por que a necessidade de passar esta mensagem e os outros para outra fila. Eu também pode parar o meu serviço e iniciá-lo novamente quando tudo está funcionando como esperado.

aogan, você tinha a resposta perfeita para MSMQ 4.0, mas infelizmente não para mim

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top