2008-09-17 16 views
17

? He creado un servicio WCF y estoy utilizando el enlace netMsmqBinding.¿Cómo manejo la falla del mensaje en los enlaces de MSMQ para WCF

Este es un servicio simple que pasa un Dto a mi método de servicio y no espera una respuesta. El mensaje se coloca en un MSMQ, y una vez recogido se inserta en una base de datos.

¿Cuál es el mejor método para asegurarse de que no se pierden datos?

He probado los 2 siguientes métodos:

  1. lanzar una excepción

    Esto coloca el mensaje en una cola de mensajes para la lectura manual. Puedo procesar este cuando mi strvice comienza

  2. conjunto del receiveRetryCount = "3" en la unión

    Después de 3 intentos - que suceden instantanously, esto parece dejar el mensaje en la cola, pero culpa que mi servicio. Reiniciar mi servicio repite este proceso.

Idealmente me gustaría hacer el seguimiento:

proceso de probar el mensaje

  • Si esto no funciona, espere 5 minutos para que el mensaje y vuelve a intentarlo.
  • Si ese proceso falla 3 veces, mueva el mensaje a la cola de mensajes no entregados.
  • Al reiniciar el servicio, todos los mensajes de la cola de mensajes no devueltos volverán a la cola para que puedan procesarse.

¿Se puede lograr esto? ¿Si es así, cómo? ¿Puede indicarme algún artículo bueno sobre la mejor manera de utilizar WCF y MSMQ para mi escena dada?

Cualquier ayuda sería muy apreciada. ¡Gracias!

Alguna información adicional

estoy usando MSMQ 3.0 en Windows XP y Windows Server 2003. Lamentablemente no puedo utilizar el soporte integrado de mensajes dañados dirigido a MSMQ 4.0 y Vista/2008.

Respuesta

9

Hay un ejemplo en el SDK que puede ser útil en su caso. Básicamente, lo que hace es adjuntar una implementación de IErrorHandler a su servicio que detectará el error cuando WCF declare que el mensaje es "venenoso" (es decir, cuando todos los reintentos configurados se hayan agotado). Lo que hace la muestra es mover el mensaje a otra cola y luego reiniciar el ServiceHost asociado con el mensaje (ya que habrá fallado cuando se encontró el mensaje de envenenamiento).

No es una muestra muy bonita, pero puede ser útil. Sin embargo, hay un par de limitaciones:

1- Si tiene varios puntos finales asociados con su servicio (es decir, expuesto a través de varias colas), no hay forma de saber a qué cola llegó el mensaje envenenado. Si solo tiene un cola única, esto no será un problema.No he visto ninguna solución oficial para esto, pero he experimentado con una alternativa posible que he documentado aquí: http://winterdom.com/weblog/2008/05/27/NetMSMQAndPoisonMessages.aspx

2- Una vez que el mensaje del problema se mueve a otra cola, se convierte en su responsabilidad, por lo Depende de usted moverlo de nuevo a la cola de procesamiento una vez que finaliza el tiempo de espera (o adjuntar un nuevo servicio a esa cola para manejarlo).

Para ser sincero, en cualquier caso, está viendo un trabajo "manual" aquí que WCF simplemente no cubre por sí mismo.

He estado trabajando recientemente en un proyecto diferente donde tengo un requisito para controlar explícitamente la frecuencia con la que se producen los reintentos, y mi solución actual era crear un conjunto de colas de reintento y mover manualmente los mensajes entre las colas de reintento y cola de procesamiento basada en un conjunto de temporizadores y algunas heurísticas, simplemente usando las cosas crudas de System.Messaging para manejar las colas de MSMQ. Parece funcionar muy bien, aunque hay un par de trampas si vas por este camino.

14

Creo que con MSMQ (disponibles sólo en Vista) que podría ser capaz de hacerlo de esta manera:

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

WCF volverá a intentar de inmediato para tiempos ReceiveRetryCount después del primer fallo de la llamada. Una vez que el lote ha fallado, el mensaje se mueve al a la cola de reintento. Después de un retraso del minuto RetryCycleDelay, el mensaje pasó de la cola de reintento a la cola del punto final y el lote se reintentó. Esto se repetirá MaxRetryCycle time.Si todo eso falla el mensaje se maneja de acuerdo con receiveErrorHandling que puede ser mover (a la cola de veneno), rechazar, eliminar o fallos

Por cierto un buen texto sobre WCF y MSMQ es la chapther 9 del libro Progammig WCF desde Juval Lowy

+0

Esto se aplica a MSMQ 4.0 no a MSMQ 3.0 – Perhentian

1

Lamentablemente estoy atascado en Windows XP y Windows Server 2003, por lo que no es una opción para mí. - (Volveré a aclarar eso en mi pregunta ya que encontré esta solución después de publicarla y me di cuenta de que no podía usarla)

Descubrí que una solución era configurar un controlador personalizado que movería mi mensaje a otra cola o envenenar la cola y reiniciar mi servicio. Esto me pareció loco. Imagine que mi servidor Sql estaba inactivo con qué frecuencia se reiniciaría el servicio.

SO, lo que he terminado haciendo es dejar que Line falle y dejar mensajes en la cola. También registro un mensaje fatal a mi servicio de registro del sistema que esto ha sucedido. Una vez que se resuelve nuestro problema, reinicio el servicio y todos los mensajes comienzan a procesarse nuevamente.

Me di cuenta de que volver a procesar este mensaje o cualquier otro fallará, así que ¿por qué la necesidad de mover este mensaje y los demás a otra fila? También puedo detener mi servicio y volver a iniciarlo cuando todo esté funcionando como se esperaba.

aogan, que tenía la respuesta perfecta para MSMQ 4.0, pero por desgracia no para mí

4

Si está utilizando SQL Server, entonces debería usar una transacción distribuida, ya que ambos MSMQ y soporte de SQL Server ella. Lo que sucede es que envuelve la escritura de su base de datos en un bloque de TransactionScope y llama a scope.Complete() solo si tiene éxito. Si falla, entonces cuando regrese su método WCF, el mensaje se volverá a colocar en la cola para volver a intentarlo. Aquí hay una versión recortada del código que utilice:

[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); 
     } 
    } 

que probar esto haciendo cola un gran pero conocido número de registros, deje WCF iniciar un montón de hilos para manejar muchos de ellos de forma simultánea (llega a 16 hilos - 16 mensajes de la cola a la vez), luego mata el proceso en el medio de las operaciones. Cuando se reinicia el programa, los mensajes se leen de nuevo desde la cola y se procesan nuevamente como si nada hubiera sucedido, y al finalizar la prueba, la base de datos es consistente y no tiene registros perdidos.

Distributed Transaction Manager tiene una presencia ambiental, y cuando crea una nueva instancia de TransactionScope busca automáticamente la transacción actual dentro del alcance de la invocación del método, que debería haber sido creada ya por WCF cuando apareció el mensaje fuera de la cola e invocó su método.

+0

Hola, Chris. Estoy seguro de que al atribuir su comportamiento de operación a TransactionScopeRequired = true se anula la necesidad de ajustar sus llamadas Sql en un ámbito de transacción, ya que esto ya se está haciendo. Dicho esto, no estoy seguro de cómo se relaciona su respuesta con mi pregunta sobre MSMQ. – WebDude

Cuestiones relacionadas