Python running MessageQueue.Peek via win32com, how to get timeout right?
Asked Answered
E

2

10

For starters, I would like to say if anyone can help here, you are incredible.

General Question

My Python program needs to interact with MSMQ. Basically, I want to peek at a queue, specifying a timeout if there's nothing in the queue.

However, despite my best efforts, I cannot get Peek() to wait out the timeout interval, when there's no value previously in the queue. Can you please point out what is missing from this code?


My Current Code

Here is my code right now:

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://learn.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

I run: inspect.getfullargspec(queue.Peek) and get:

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

Things I've Tried

This question: saying ReceiveTimeout=timespan doesn't seem to solve my problem.

Replacing pythoncom.Empty with pythoncom.Missing doesn't seem to work

This unanswered question seems very similar to mine

Eyetooth answered 31/10, 2019 at 23:57 Comment(4)
pythoncom has CoWaitForMultipleHandles(Flags, Timeout , Handles ) does it helps you ?Antonio
Hi @Antonio do you mind elaborating? It may help, it sort of seems like a workaround though. I am wondering how to get args right for timeout on queue.PeekEyetooth
Just a thought, but other examples I've seen of of this interface in Python simply use an integer (in milliseconds) for their timeout. Maybe pywin32 isn't handling TimeSpans the way you expect...Kootenay
@PeterBrittain thank you, that actually did the trick! I posted your comment as the answer below.Eyetooth
E
1

In the original question's comments, @PeterBrittain suggested to try just using:

an integer (in milliseconds) for their timeout

I got around to trying that out, and actually, it worked! I found float values to work as well. Here is some sample Python code:

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

Thank you @PeterBrittain!

Eyetooth answered 11/11, 2019 at 21:56 Comment(0)
A
0

I found this article sending-msmq-messages-python

The article shows you how to send and receive a message using msmq. I don't understand why you can't just standard socket connection syntax to say if I haven't received a packet/connection then close connection

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

So something like that shouldn't be too difficult. Worst case scenario create a thread that checks every timeout_time if a variable is zero or not. If it's zero close queue nothing received if it's >0 set to zero and wait for more messages. I also found a GitHub about asynchronous msmq for python logging. asynchronous msmq This one just said receive while 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}')

Not the answer you wanted but one that will work.

Aldoaldol answered 10/11, 2019 at 6:14 Comment(2)
Hello @MichaelHearn! Thank you for providing multiple useful workarounds. As such, I am awarding you the bounty :)Eyetooth
Thank you! @IntrastellarExplorerAldoaldol

© 2022 - 2024 — McMap. All rights reserved.