I am trying to read messages on a MQTT server. In some cases, the connection is unstable and requires to reconnect. But after reconnect, I am not able to receive any message from the topic that I previously subscribed to. I am using paho's python package to handle MQTT connection. Here is some code I am using
TopicName='some/topic/name'
class Counter:
def __init__(self, mqttClient):
self.messages_recieved = 0
self.mqttClient = mqttClient
self.mqttClient.subscribe(TopicName)
self.mqttClient.on_message = self.on_message
self.mqttClient.on_disconnect = self.on_disconnect
self.mqttClient.loop_start()
def on_message(self, client, userdata, message):
self.messages_received += 1
def on_disconnect(self, client, userdata, rc):
if rc != 0:
print("Trying to reconnect")
while not self.mqttClient.is_connected():
try:
self.mqttClient.reconnect()
except OSError:
pass
If my internet goes down, I am no longer able to receive messages. I have tried to subscribe again to the topic, also I have tried to call loop_start in the on_disconnect method, neither of those worked. Any solution would be helpful. Also to point out messages are being sent, I can see them in the browser on MQTT wall
You have not shown where you are calling connect, but the usual safe pattern is to put the calls to subscribe() in the on_connect() callback attached to the client.
This means that calls to subscribe will
Always wait until the connection has completed
Get called again automatically when a reconnect had happend
Not sure what module you are using, but most will require you to re-subscribe if you disconnect. Add your subscribe() call after your .reconnect() call and you should be good to go. Also, keep in mind that at QOS level 0, any messages that the broker received while you were disconnect, your client will NOT receive...only messages while the client is subscribed will be received by your client. If messages are published with the Retain flag, you client will receive the LAST one received by the broker...even if the client previously received it.
Related
My Paho MQTT client does the following:
Subscribe to mytopic/#
Do something
Publish to mytopic/#
Problem:
The published message in step 3 arrives at step 1. I'd like to avoid adding a sender-attribute to the payload.
Is there a proper way of ignoring self-published messages? Something like the following (pseudocode):
def on_message(self, client, userdata, message):
if client.id == message.sender_client_id: # Is there anything like the sender_client_id?
return
Any idea? Thanks!
As of the MQTT v5 spec you can tell the broker not to send your own messages back to you as part of the subscription message.
This removes the need to add the identifier so you can then choose to ignore it.
This does of course rely on both the broker and the MQTT client supporting MQTT v5
This logic should work:
Assign an id to every client
every client publish on mytopic/{id}
every client sub to mytopic/#
ignore messages where message.topic starts with mytopic/{id}
If you are using MQTT v5, you can pass the noLocal option to the paho client when subscribing. This option tells the broker not to send back your own messages.
from paho.mqtt.subscribeoptions import SubscribeOptions
...
options = SubscribeOptions(qos=1, noLocal=True)
client.subscribe('mytopic/#', options=options)
def on_message(self, client, userdata, message):
if client.id == message.sender_client_id: # Is there anything like the sender_client_id?
return
In your pseudocode, you are asking for the client's identity but this is exactly opposite to the MQTT specification. In MQTT, two different clients are unaware of each other's identity, they only communicate via the MQTT broker by subscribing to the topics.
I am sending a number of messages simultaneously from multiple clients from one python script and trying to receive them on another script. The problem I am getting is that the message is received but only from the first client that gets connected and it keeps on looping over it.
What I need to have is that I get messages from each client in the manner they are published.
import paho.mqtt.client as mqtt
import time
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to broker")
global Connected
Connected = True
else:
print("Connection failed")
def on_message(client, userdata, message):
print ("Message received: " + str(message.payload) + " from " + str(client))
Connected = False
client = mqtt.Client()
client.on_connect= on_connect
client.on_message= on_message
client.connect(host)
client.loop_start()
while Connected != True:
time.sleep(0.1)
client.subscribe("test")
print("subscribed")
client.loop_stop()
You are misunderstanding what the client argument in the on_message callback is.
This value is a link to the local instance of the MQTT client that has subscribed to the topic.
MQTT messages do not carry any information about the client that published them, unless you explicitly encode it into the payload. Part of the point of a Pub/Sub protocol like MQTT is to totally decouple the information creator (publisher) from the information consumer (subscriber).
Also you should move the call to client.subscribe("test") to inside the on_connect() callback because as you have it you are trying to resubscribe to the same topic 10 times a second which will achieve absolutely nothing, except to generate unneeded load on the broker.
I have a durable subscriber for a topic(eg:topic_a). I am trying to provide client-individual ACK. At the end of the try block, I am providing manual ack and in exception block, I am doing no acknowledgment. Whenever an error occurs the consumer(subscriber) is getting hung up and eventually stops.
I AM TRYING TO DO MANUAL ACK IN TOPIC(PUB-SUB) BASED IMPLEMENTATION.
1). Is it possible?
2). Whether the message will be redelivered to the same durable subscriber?
execute method inside main class:
self.conn = stomp.Connection11(self.conn_param, encoding=self.ENCODE_FORMAT)
self.conn.start()
self.conn.connect(wait=True, headers={'client-id': self.CLIENT_ID})
self.conn.set_listener('', CustomListener(self.conn))
Listener class:
class CustomListener(stomp.ConnectionListener):
def __init__(self, conn, func_to_exec):
self.conn = conn
def on_message(self, headers, message):
try:
message = json.loads(message)
/**DO SOME BUSINESS LOGIC**/
self.conn.ack(headers.get("message-id"), int(headers.get("subscription")))
print("message ack done..!")
except Exception as ex:
print("Exception in processing message :: %s"%(ex))
in on_message Listener if any exception during process time. then the message needs to redelivered.
If using client individual ack mode then your code has a responsibility to acknowledge the messages sent to it and if you fail to ack enough then the broker would stop sending you more because you've exhausted the available credit that is configured. The broker would assume the unacknowledged messages are pending until you either ACK or NACK them. You can use NACK to poison the message and either send it to DLQ or (if configured broker side redelivery) have the broker redeliver the message.
I am trying to get message from activemq using stomp.py and then doing some processing on it. But there is a case when that processing fails for certain messages and that message is lost.
How can I prevent the deletion of message untill the message is fully processed?
For example in my code when there is new entry in queue the on_message function will be called and the processing starts but if it is interrupted in between the message is lost. How do I stop it?
Here is my code:
conn = stomp.Connection([(host, 61613)])
conn.set_listener('ML', MyListener())
conn.start()
conn.connect('admin', 'admin', wait=True)
conn.subscribe(destination=/queue/someque, id=1, ack='auto')
print "running"
while 1:
print 'waiting'
time.sleep(2.5)
Here is my Listener class:
class MyListener(stomp.ConnectionListener):
def on_message(self, headers, message):
print headers
print message
do_something()
Thanks in advance.
The issue appears to be that you are using the 'auto' ack mode so the message will be acknowledged before delivery to the client by the broker meaning that even if you fail to process it, it's to late as it is already forgotten on the broker side. You'd need to use either 'client' ack or 'client-individual' ack mode as described in the STOMP specification. Using one of the client ack modes you control when a message or messages are actually acknowledged and dropped by the broker.
I have an autobahn Websocket Server with the typical onX functions in it's protocol. My problem is that I can't find a way to exit onX, while keep doing the various stuff that I wanted to do when the specific message arrived. More specifically in my onMessage function, I sometimes perform an HTTP request to an API which is very slow. As a result, the client that sent the websocket message is being blocked by the server's onMessage finalization. Even if I do self.sendMessage or reactor.callFromThread(<http request here>), or self.transport.loseConnection() from the server side, in the onMessage block, the onMessage is still executing the HTTP request and my client waits.
This is my client's code:
#asyncio.coroutine
def send(command,userPath,token):
websocket = yield from websockets.connect('wss://127.0.0.1:7000',ssl=ssl.SSLContext(protocol=ssl.PROTOCOL_TLSv1_2))
data = json.dumps({"api_command":"session","body":command,"headers": {'X-User-Path': userPath, 'X-User-Token': token}})
response = {}
try:
yield from websocket.send(data)
finally:
yield from websocket.close()
if 'command' in response:
if response['command'] == 'ACK_SESSION_COMMAND' or response['command'] == 'ACK_INITIALIZATION':
return ('OK',200)
else:
return('',400)
I even tried to just websocket.send(data), from the client, but for some reason it doesn't send the data (I don't see them arriving in the server). I don't understand how can I return from the onMessage block and keep doing my HTTP request.
And to explain my situation, I just want to sent 1 ssl websocket message to my server and immediately close the connection. Anything that can do that, suits me.
Using reactor.callInThread instead of reactor.callFromThread, causes the application flow to release and the HTTP request is performed independently in a thread. As described in the twisted documentation : http://twistedmatrix.com/documents/13.2.0/core/howto/threading.html