Python ejecutando MessageQueue.Peek a través de win32com, ¿cómo obtener el tiempo de espera correcto?

9

Para empezar, me gustaría decir que si alguien puede ayudar aquí, eres increíble.

Pregunta general

Mi programa Python necesita interactuar con MSMQ. Básicamente, quiero echar un vistazo a una cola, especificando un tiempo de espera si no hay nada en la cola.

Sin embargo, a pesar de mis mejores esfuerzos, no puedo hacer que Peek () espere el intervalo de tiempo de espera, cuando no hay ningún valor previamente en la cola. ¿Puedes señalar lo que falta en este código?


Mi código actual

Aquí está mi código en este momento:

from socket import gethostname

import win32com.client
import pythoncom

import clr
clr.AddReference("System")
clr.AddReference("System.Messaging")
from System import TimeSpan
from System.Messaging import MessageQueue


# Source: [1]
# [1] https://docs.microsoft.com/en-us/previous-versions/windows/desktop/msmq/ms707027%28v%3dvs.85%29
MQ_DENY_NONE = 0x0
MQ_PEEK_ACCESS = 0x1
MQ_SEND_ACCESS = 0x2


# Set up queue
pythoncom.CoInitialize()
qinfo = win32com.client.Dispatch("MSMQ.MSMQQueueInfo")
qinfo.FormatName = f"direct=os:{gethostname()}\\PRIVATE$\\MyQueue"
queue = qinfo.Open(MQ_PEEK_ACCESS, MQ_DENY_NONE)

# Receive a value
timeout_sec = 1.0
timespan = TimeSpan.FromSeconds(timeout_sec)
label, body = "", ""
# TODO: timeout value does not appear working. It never waits when
#  there's no message
if queue.Peek(pythoncom.Empty, pythoncom.Empty, timespan):
    msg = queue.Receive() . # Blocking receive --> remove msg from the queue
    if msg is not None:
        label = msg.Label
        body = msg.Body

Corro: inspect.getfullargspec(queue.Peek)y obtengo:

FullArgSpec(args=['self', 'WantDestinationQueue', 'WantBody', 'ReceiveTimeout', 'WantConnectorType'], varargs=None, varkw=None, defaults=(<PyOleMissing object at 0x00000147F5D43BD0>, <PyOleMissing object at 0x00000147F5D43BD0>, <PyOleMissing object at 0x00000147F5D43BD0>, <PyOleMissing object at 0x00000147F5D43BD0>), kwonlyargs=[], kwonlydefaults=None, annotations={})

Cosas que he probado

Esta pregunta : decir ReceiveTimeout=timespanno parece resolver mi problema.

Reemplazar pythoncom.Emptycon pythoncom.Missingno parece funcionar

Esta pregunta sin respuesta parece muy similar a la mía.

Explorador intraestelar
fuente
Pythoncom tiene CoWaitForMultipleHandles(Flags, Timeout , Handles )¿te ayuda?
LinPy
Hola @LinPy, ¿te importaría elaborar? Puede ayudar, aunque parece una solución alternativa. Me pregunto cómo obtener argumentos adecuados para el tiempo de esperaqueue.Peek
Intrastellar Explorer
1
Solo un pensamiento, pero otros ejemplos que he visto de esta interfaz en Python simplemente usan un número entero (en milisegundos) para su tiempo de espera. Tal vez pywin32 no esté manejando TimeSpans de la manera que espera ...
Peter Brittain
@ PeterBrittain gracias, ¡eso realmente funcionó! Publiqué tu comentario como la respuesta a continuación.
Intrastellar Explorer

Respuestas:

0

Encontré este artículo enviando-msmq-messages-python

El artículo muestra cómo enviar y recibir un mensaje usando msmq. No entiendo por qué no puede simplemente sintaxis de conexión de socket estándar para decir si no he recibido un paquete / conexión y luego cerrar la conexión

import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
    data = mysocket.recv(4096)

Entonces, algo así no debería ser demasiado difícil. En el peor de los casos, cree un hilo que verifique cada timeout_time si una variable es cero o no. Si es cero, no se recibe nada si es> 0 establecido en cero y espera más mensajes. También encontré un GitHub sobre msmq asíncrono para el registro de python. msmq asíncrono Éste acaba de decir recibir mientras verdadero dlopes7 msmq

import time
t_end = time.time() + 60 * 15
messages=0
while time.time() < t_end or messages>0:
    msg = queue.Receive()
    messages+=1
    if(time.time() > t_end and messages>0):
        messages=0
        t_end = time.time() + 60 * 15
    print(f'Got Message from {queue_name}: {msg.Label} - {msg.Body}')

No es la respuesta que quería, sino una que funcionará.

Michael Hearn
fuente
Hola @MichaelHearn! Gracias por proporcionar varias soluciones alternativas útiles. Como tal, te estoy otorgando la recompensa :)
Intrastellar Explorer
¡Gracias! @IntrastellarExplorer
Michael Hearn
0

En los comentarios de la pregunta original, @PeterBrittain sugirió probar simplemente usando:

un entero (en milisegundos) para su tiempo de espera

Tuve la oportunidad de probar eso, y en realidad, ¡funcionó! Encontré floatvalores para trabajar también. Aquí hay un código de Python de muestra:

timeout_sec = 1.0
queue.Peek(pythoncom.Empty, pythoncom.Empty, timeout_sec * 1000):

¡Gracias @PeterBrittain!

Explorador intraestelar
fuente