← index #321Issue #102
Duplicate · high · value 5.092
QUERY · ISSUE

Umqtt.robust: subscription vanished after reconnect

openby JDchauhanopened 2018-11-27updated 2023-08-12

Board used
ESP8266

What is the problem:
Umqtt.robust() on reconnection will forget the previously subscribed topics i.e, it do not fetch messages of subscribed topics after reconnection.

When the problem occurs (how to mimic it)
after successful subscription of topics and verifying that everything works fine just turn off your internet connection. Then after 5 minutes restart internet connection.

(Note: try to use publish-message with try-catch before check_msg() otherwise u might get stuck with #192 )

Then you will observe that no message is being fetched by the check_msg() on that topic.

How to solve this
This might not be a good solution but for now, I am just subscribing all the topics again whenever the connection lost

12 comments
kevinkk525 · 2018-12-03

That's the only working solution and the best one. I'm doing so as well with another mqtt client.
The only other solution would be to connect without a clean connect but that can result in getting all missed messages between connection loss and reconnection and is therefore not advised to do as it would likely crash your small microcontroller.

turutupa · 2020-02-11

How to you re-subscribe to all topics on connection lost??

kevinkk525 · 2020-02-11

You have all your subscriptions stored and on reconnect you just subscribe all of them.

turutupa · 2020-02-11

But I mean. If on my main while loop I only have client.wait_msg(). Where exactly do I execute the re-subscribe? Is there an onconnect / onreconnect function or something like this? (thanks for the quick response btw!)

kevinkk525 · 2020-02-11

Hmm you are right, the umqtt.robust doesn't really offer a convenient way of recognizing a reconnect.. I haven't used this code in years. I use an async mqtt client https://github.com/peterhinch/micropython-mqtt

It looks like you need to create a subclass so you can change the way the reconnect works so you can subscribe after a reconnect.
But maybe someone else who actually uses this code has a better solution.

JDchauhan · 2020-02-12

How to you re-subscribe to all topics on connection lost??

I have maintained list of subscribed topic in my code itself, Whenever It gots to know about disconnection and gets reconnected I will again subscribing them, for prompt of disconnect I am running the publish event (just for checking) in the try block and checking problems in catch if any comes

turutupa · 2020-02-12

UUuuuh, nice. Hadn´t thought about publishing just to check if it is subscribed to a topic, nice approach! Mainly cause I have only used umqtt to receive messages.

Now I fully understand your note

try to use publish-message with try-catch before check_msg() otherwise u might get stuck with #192 )

Thanks!

turutupa · 2020-02-27

Hey guys, I am back and not with good news hehe.. I was wondering, @JDchauhan could you provide code to your publish-subscribe? I haven't spent too much time on this, but I must admit I haven't managed to make it work. I have tried to try-catch publish and then check_msg but it gives me mqtt: OSError(-1,)

Hoping to find a robust way to make it work

IMPORTANT EDIT: forgot to mention. If I only publish every 5 ~ 10 seconds its fine. It does publish. Gives me error when I check_msg() after publishing

I have to add I am using Adafruit IO to publish-subscribe... could that be issue? What service are you using? Perhaps I should run my own mosquitto on a pi? I rather use Adafruit for IFTTT...

alessionossa · 2023-06-14

Hey guys, I am back and not with good news hehe.. I was wondering, @JDchauhan could you provide code to your publish-subscribe? I haven't spent too much time on this, but I must admit I haven't managed to make it work. I have tried to try-catch publish and then check_msg but it gives me mqtt: OSError(-1,)

Hoping to find a robust way to make it work

IMPORTANT EDIT: forgot to mention. If I only publish every 5 ~ 10 seconds its fine. It does publish. Gives me error when I check_msg() after publishing

I have to add I am using Adafruit IO to publish-subscribe... could that be issue? What service are you using? Perhaps I should run my own mosquitto on a pi? I rather use Adafruit for IFTTT...

Seeing the exact same issue, with Adafruit IO too.

JDchauhan · 2023-07-22

Hi @turutupa & @alessionossa
I was using my own MQTT broker at that time.

Below is the part of the code I used back then that worked for me. I don't remember exactly but from the code, it seems like I am expecting the error to be thrown by check_msg() instead of publish() and then subscribing again (if it helps)

            try:
                client.publish(topic="test", msg="testing")
                if not isBroker:
                    client.subscribe(topic= data["id"] + "/#")                     
                # print("connected")
                client.check_msg()
                time.sleep(0.5)
            except:
                isBroker = False
                print("broker disconnected")
                time.sleep(2)
                break
javiergmarcos · 2023-08-12

Same on my side. I'm using micropython on ESP32 C3. Next the workaround that works for me.
Main loop blocking:
In the main() loop, I've replaced the mqtt.robust check_msg() and wait_msg() by my own, because if there is no mqtt server, check_msg() is waiting forever. That happens because when it calls to wait_msg(), it waits forever instead of generate an exception that try to reconnect and then continue the main() loop
The problem arise because check_msg() set self.mqtt_client.sock.setblocking(False), and then calls to wait_msg()
On their side wait_msg() change self.mqtt_client.sock.setblocking(True) at its beginning, and then allowing to wait for a mqtt server connection.
My workaround is using my_check_msg(), that is an exact copy of the check_msg() except it calls my_wait_msg().
my_wait_msg() is an exact copy of wait_msg() except that the initial #self.mqtt_client.sock.setblocking(True) is commented.
I've tried this with class inheritance and monkey patching without success. May be side effects
Regenerate subscription mqtt:
All my appliances (sensor, switch, light,...) connected to mqtt have a _register_mqtt(self) procedure.
In the initial setup of every appliance, I add each appliance to a device_appliances{} dictionary (key=appl_id, value=appliance) and also call _register_mqtt(self)
To reconnect after a mqtt server (or Wifi) fault, the procedure reinitialize the mqtt_client and then calls the _register_mqtt() for each appliance in the device_appliances{} dictionary.
Finally also republish the availability_topic.

andrewleech · 2023-08-12

Subclass is the current recommended solution here, however it won't really work until this is merged. Take a look for more information & example about re-subscription
https://github.com/micropython/micropython-lib/pull/669

CANDIDATE · ISSUE

umqtt.robust dies when MQTT broker gets restarted

openby phieberopened 2016-09-14updated 2024-08-25

Hi,

the umqtt.robust module is pretty reliable but I found a case when it stops sending:

screenshot from 2016-09-14 13 42 10

As soon as I restart the MQTT broker, I have to connect via WebREPL and press CTRL+C.

I use the following minimal test code:
https://github.com/phieber/uPython-ESP8266-01-umqtt

Can you reproduce this issue when restarting the broker?

br
Patrick

16 comments
phieber · 2016-09-14

In the screenshot above, I have restarted the broker after two successful MQTT publish messages (two temperature values in this case)

Actpohomoc · 2016-11-09

I use code to avoid such problem:

try: retries = 0 while (retries < 20): retries += 1; client.check_msg() time.sleep(1); except OSError: connect_and_subscribe()

def connect_and_subscribe():
global client
client = MQTTClient(CONFIG['client_id'], CONFIG['broker'], CONFIG['port'], "user", "pass", 120)
client.set_callback(callback)
client.connect(False)
print("Conn to {}".format(CONFIG['broker']))
client.subscribe(b"MBI/CURRENT_DATETIME")
time.sleep(1);
client.check_msg()
.....
So I always check if there any OsError and reconnect to MQTT.

You need to upgrade the robust by this PR: [https://github.com/micropython/micropython-lib/pull/117]

craftyguy · 2017-03-17

Is there a better way to go about handling this situation where the broker 'disappears' and then 're-appears' at some later time? The current implementation of umqtt.robust is not robust at all, even with the reconnect. check_msg never works even though it seems the client reconnected.

Should the umqtt.robust object include a list of subscribed topics to auto-resubscribe in the reconnect() function?

scargill · 2017-06-01

That last message as a microPython newby worries me... I don't want to start coding in microPython on the basis of unreliable MQTT as we have reliable MQTT in C......

Can someone give an example of this "robust" code which WILL stay connected and which will resubscribe on reconnection - i.e. so that it just works in the background.

Is this possible?

dpgeorge · 2017-06-02

Is there a better way to go about handling this situation where the broker 'disappears' and then 're-appears' at some later time?

Yes, the current implementation of umqtt.robust does not handle the case when the broker is restarted and forgets all of its state (at least the state related to your client).

Should the umqtt.robust object include a list of subscribed topics to auto-resubscribe in the reconnect() function?

Prehaps. This is indeed how other libraries work (eg https://github.com/fusesource/mqtt-client). The robust MQTTClient class would need to override the "subscribe" method to record the topics (and qos), and then in the reconnect() method it would call subscribe() again after reconnecting.

dpgeorge · 2017-06-02

See #186 for a fix which will resubscribe to all existing topics if a reconnect is made.

craftyguy · 2017-06-02

Damn, I was in the process of writing a fix for this. You win the day, sir!

dpgeorge · 2017-06-02

@craftyguy I'd be interested to see your solution. And also if you want to test my solution and give feedback that would be great.

craftyguy · 2017-06-02

I literally started about less than an hour ago, but my approach was pretty much the same as yours. Your solution looks to be more elegant/robust. I'll give this a shot possibly as early as tomorrow, since I'm tired of hacking together a more robust robust mqtt :smile:

craftyguy · 2017-06-03

@dpgeorge

I tried your patch (#186), and it doesn't seem to work with this simple test program:

import machine
from umqtt.robust import MQTTClient
import utime

MQTT_SERVER = '1.1.1.1'
IN = 'in'
OUT = 'out'

# mqtt subscription callback
def sub_cb(topic, msg):
    t = topic.decode('ASCII')
    m = msg.decode('ASCII')
    print("received new topic/msg: %s / %s" % (t, m))
    if t == IN:
        print("IN: %s" % m)

umqtt_client = MQTTClient("test_client", MQTT_SERVER)
umqtt_client.DEBUG = True
umqtt_client.set_callback(sub_cb)
umqtt_client.connect(clean_session=False)
umqtt_client.subscribe(IN)
print("Connected to MQTT broker: %s" % MQTT_SERVER)


def main():
    global umqtt_client
    while True:
        utime.sleep(1)
        umqtt_client.check_msg()
        umqtt_client.publish(OUT, b'hi!')

I should note that I am invoking the main() function here from main.py.

When I restart the mqtt broker, I get an mqtt: OSError(-1,) printed to console. I can see the client reconnects to the broker since there's a message in the broker log about this, but the client doesn't respond to messages published to the IN topic, nor does it publish anything else to OUT topic.

If my test is an invalid use of umqtt, please let me know since I am relatively new to using mqtt!

dpgeorge · 2017-06-06

@craftyguy for your example to work I think you need to connect with clean_session=True, because you'll be explicitly resubscribing upon reconnection.

craftyguy · 2017-06-07

@dpgeorge I see, thank you for pointing that out. I also see the PR was merged :)
I will give it another try!

dpgeorge · 2017-06-07

I also see the PR was merged

@craftyguy No it wasn't, so you'll need to pull the PR explicitly to test it.

craftyguy · 2017-06-07

Ugh, I guess I misinterpreted a notification I received, now I see it
was you just modifying the PR. Sorry!

On Tue, Jun 06, 2017 at 09:53:05PM -0700, Damien George wrote:

I also see the PR was merged

@craftyguy No it wasn't, so you'll need to pull the PR explicitly to test it.

--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
https://github.com/micropython/micropython-lib/issues/102#issuecomment-306686107

curiouswala · 2018-06-22

I tried the PR and it does recover from a broker restart but when the broker loses power and comes back, it doesn't recover. It is completely reproducible, happens every time I take the power out from my raspberry pi zero running the mosquitto broker. Does anyone else face this behaviour?
The problem seems to be that umqtt.robust does raise an error when killing my mqtt broker from the terminal but doesn't raise any error when broker dies from a power outage.

jonnor · 2024-08-25

Is this still an issue on latest MicroPython and mqtt.robut? If so, we need minimal example code on how to reproduce.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied