Actualmente estoy teniendo problemas para perder un mensaje. Este error ocurre raramente, pero sucede con suficiente frecuencia como para ser molesto. Aquí está el contexto del problema:¿Es posible perder mensajes usando MSMQ MessageQueue.Peek con un tiempo de espera excedido?
- He activado el diario de mensajes en goldmine_service_queue, un MSMQ en el servidor de Windows 2003.
- Puedo probar que el mensaje se está insertando en goldmine_service_queue ya que el mensaje aparece en el diario de mensajes. Esta información proporciona información de tiempo sobre cuándo desapareció el mensaje.
- Las funciones de registro utilizan http://logging.apache.org/log4net/index.html
- Los registros no muestran errores.
- La función de trabajador (que se muestra a continuación) se ejecuta dentro de un hilo de un servicio de Windows. Es responsable de echar un vistazo a los mensajes (elementos de trabajo) de la cola y procesarlos.
- De los registros, sospecho fuertemente que mi problema podría estar relacionado con MessageQueue.Peek y el comportamiento de tiempo de espera.
¿Es posible que se produzca el tiempo de espera y la recepción del mensaje al mismo tiempo? ¿Hay una manera mejor para mí de manejar la comprobación de detención del servicio para ayudar a evitar este error?
private void workerFunction()
{
logger.Info("Connecting to queue: " + Settings.Default.goldmine_service_queue);
MessageQueue q = new MessageQueue(Settings.Default.goldmine_service_queue);
q.Formatter = new ActiveXMessageFormatter();
while (serviceStarted)
{
Message currentMessage = null;
try
{
currentMessage = q.Peek(new TimeSpan(0,0,30));
}
catch (System.Messaging.MessageQueueException mqEx)
{
if (mqEx.ToString().Contains("Timeout for the requested operation has expired"))
{
logger.Info("Check for service stop request");
}
else
{
logger.Error("Exception while peeking into MSMQ: " + mqEx.ToString());
}
}
catch (Exception e)
{
logger.Error("Exception while peeking into MSMQ: " + e.ToString());
}
if (currentMessage != null)
{
logger.Info(currentMessage.Body.ToString());
try
{
ProcessMessage(currentMessage);
}
catch (Exception processMessageException)
{
logger.Error("Error in process message: " + processMessageException.ToString());
}
//Remove message from queue.
logger.Info("Message removed from queue.");
q.Receive();
//logPerformance(ref transCount, ref startTime);
}
}//end while
Thread.CurrentThread.Abort();
}
Gracias por la respuesta: - en lo que respecta a las condiciones de carrera: No estoy seguro de si veo las condiciones de carrera que está mencionando. De acuerdo con http://msdn.microsoft.com/en-us/library/t5te2tk0.aspx, MessageQueue.Peek (Timeout) es una llamada de bloqueo. - Me preocupa utilizar un patrón asíncrono ya que ProcessMessage realiza algunas operaciones COM. No sé si estas operaciones son seguras para hilos. Estoy de acuerdo con intentar utilizar Receive() en lugar de peak excepto que no sé cómo crear la oportunidad de detener el ciclo while debido a una parada del servicio. –
Re: COM en 'ProcessMessage': no debería ser un problema si solo un subproceso está ejecutando' ProcessMessage' (que se puede lograr en el caso async iniciando una nueva recepción asincrónica después de que 'ProcessMessage' se haya completado. En la asincrónica caso de que cierre la cola (y vacíe la memoria caché --- en función de algunas búsquedas esto parece ser necesario para cerrar realmente la conexión) y cualquier recepción pendiente será cancelada. No hay ningún ciclo para cancelar. – Richard