Python executando MessageQueue.Peek via win32com, como obter o tempo limite certo?

9

Para começar, eu gostaria de dizer que se alguém puder ajudar aqui, você é incrível.

Pergunta Geral

Meu programa Python precisa interagir com o MSMQ. Basicamente, quero espiar uma fila, especificando um tempo limite se não houver nada na fila.

No entanto, apesar dos meus melhores esforços, não consigo Peek () aguardar o intervalo de tempo limite, quando não há valor anteriormente na fila. Você pode apontar o que está faltando nesse código?


Meu Código Atual

Aqui está o meu código agora:

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

Eu corro: inspect.getfullargspec(queue.Peek)e recebo:

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={})

Coisas que eu tentei

Esta pergunta : dizer ReceiveTimeout=timespannão parece resolver o meu problema.

Substituir pythoncom.Emptypor pythoncom.Missingnão parece funcionar

Esta pergunta sem resposta parece muito semelhante à minha

Explorador Intrastelar
fonte
pythoncom tem CoWaitForMultipleHandles(Flags, Timeout , Handles )isso ajuda você?
LinPy 5/11/19
Oi @LinPy, você se importa em elaborar? Pode ajudar, mas parece uma solução alternativa. Eu estou querendo saber como obter args certo para tempo limite emqueue.Peek
intrastellar Explorador
11
Apenas um pensamento, mas outros exemplos que eu vi dessa interface no Python simplesmente usam um número inteiro (em milissegundos) para o tempo limite. Talvez pywin32 não está a lidar com TimeSpans da maneira esperada ...
Peter Brittain
@ PeterBrittain obrigado, que realmente fez o truque! Publiquei seu comentário como resposta abaixo.
Explorer Intrastellar

Respostas:

0

Encontrei este artigo enviando-msmq-messages-python

O artigo mostra como enviar e receber uma mensagem usando o msmq. Eu não entendo por que você não pode simplesmente sintaxe de conexão de soquete padrão para dizer se eu não recebi um pacote / conexão e fechei a conexão

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

Então, algo assim não deve ser muito difícil. No pior cenário, crie um encadeamento que verifique a cada timeout_time se uma variável é zero ou não. Se for zero, feche a fila, nada será recebido se for> 0 definido como zero e aguarde mais mensagens. Eu também encontrei um GitHub sobre msmq assíncrono para log em python. msmq assíncrono Este disse apenas receber enquanto True 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}')

Não é a resposta que você queria, mas uma que funcione.

Michael Hearn
fonte
Olá @MichaelHearn! Obrigado por fornecer várias soluções úteis. Como tal, estou concedendo-lhe a recompensa :)
intrastellar Explorador
Obrigado! @IntrastellarExplorer
Michael Hearn
0

Nos comentários da pergunta original, @PeterBrittain sugeriu tentar apenas usar:

um número inteiro (em milissegundos) para o tempo limite

Eu tentei fazer isso e, na verdade, funcionou! Encontrei floatvalores para trabalhar também. Aqui está um exemplo de código Python:

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

Obrigado @PeterBrittain!

Explorador Intrastelar
fonte