Python z systemem MessageQueue.Peek za pośrednictwem win32com, jak uzyskać odpowiedni limit czasu?

9

Na początek chciałbym powiedzieć, że jeśli ktoś może tu pomóc, jesteś niesamowity.

Pytanie ogólne

Mój program Python musi wchodzić w interakcje z MSMQ. Zasadniczo chcę zerknąć do kolejki, określając limit czasu, jeśli nie ma nic w kolejce.

Jednak pomimo moich najlepszych starań nie mogę zmusić Peek () do przekroczenia limitu czasu, gdy wcześniej nie ma żadnej wartości w kolejce. Czy możesz wskazać, czego brakuje w tym kodzie?


Mój obecny kod

Oto mój kod w tej chwili:

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

Biegam: inspect.getfullargspec(queue.Peek)i dostaję:

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

Rzeczy, które próbowałem

To pytanie : powiedzenie ReceiveTimeout=timespannie rozwiązuje mojego problemu.

Wymiana pythoncom.Emptyz pythoncom.Missingnie wydają się działać

To pytanie bez odpowiedzi wydaje się bardzo podobne do mojego

Intrastellar Explorer
źródło
pythoncom ma ci CoWaitForMultipleHandles(Flags, Timeout , Handles )to pomóc?
LinPy,
Cześć @LinPy, czy masz coś przeciwko opracowaniu? Może to pomóc, ale wydaje się, że to obejście. Zastanawiam się, jak uzyskać argumenty na czasqueue.Peek
Intrastellar Explorer
1
To tylko myśl, ale inne przykłady tego interfejsu w Pythonie wykorzystują po prostu liczbę całkowitą (w milisekundach) do przekroczenia limitu czasu. Może pywin32 nie obsługuje TimeSpans w oczekiwany sposób ...
Peter Brittain,
@PeterBrittain dziękuję, że to naprawdę załatwiło sprawę! Twój komentarz zamieściłem jako odpowiedź poniżej.
Intrastellar Explorer,

Odpowiedzi:

0

Znalazłem ten artykuł wysyłanie-msmq-messages-python

W tym artykule pokazano, jak wysyłać i odbierać wiadomości za pomocą msmq. Nie rozumiem, dlaczego nie można po prostu użyć standardowej składni połączenia gniazda, aby powiedzieć, że jeśli nie otrzymałem pakietu / połączenia, to zamknij połączenie

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

Coś takiego nie powinno być zbyt trudne. Scenariusz najgorszego przypadku tworzy wątek, który sprawdza za każdym razem timeout_time, czy zmienna ma wartość zero, czy nie. Jeśli jest to zerowa kolejka zamknięta, nic nie zostanie odebrane, jeśli jest> 0 ustawione na zero i czeka na więcej wiadomości. Znalazłem również GitHub o asynchronicznym msmq do rejestrowania w Pythonie. asynchroniczny msmq Ten właśnie powiedział, że odbiera, podczas gdy 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}')

Nie odpowiedź, którą chciałeś, ale taka, która zadziała.

Michael Hearn
źródło
Cześć @MichaelHearn! Dziękujemy za udostępnienie wielu przydatnych obejść. W związku z tym
przyznam
Dziękuję Ci! @IntrastellarExplorer
Michael Hearn
0

W komentarzach do pierwotnego pytania @PeterBrittain sugerował, aby spróbować po prostu użyć:

liczba całkowita (w milisekundach) dla ich limitu czasu

Zacząłem próbować tego i faktycznie zadziałało! Znalazłem floatwartości, które również działają. Oto przykładowy kod Python:

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

Dziękuję @PeterBrittain!

Intrastellar Explorer
źródło