How to prevent function reentries?

Hello all,

The setup include:

  • MKR1010WIFI
  • ArduinoMqttClient library
  • Mosquitto broker

The program includes mqttClient.onMessage(myFunc), everything works fine until the unit receives a sequence of messages and not enough time in between to complete handling each message. This is causing reentries to myFunc and subsequently bricks the unit.

Is there a way to prevent re-entries?

Alternatively, is it possible cancel onMessage as the program enters myFunc and call it again when exiting?

Any other suggestions?

Thanks!

Any other suggestions?

Yes.

Read read this before posting a programming question then post your code

I'm not familiar with the details of mqttClient.onMessage() but I suspect it is possible to disable it as the first thing within your function and re-enable it as the last thing in the function.

HOWEVER, I suspect the real problem is that your code is spending too long in your function.

But you have not posted your program.

...R

Fair enough. here's the relevant parts of the 1200 line program, obviously not a running code:

#include <WiFiNINA.h>
#include <ArduinoMqttClient.h>

WiFiClient      wifiClient;
MqttClient      mqttClient(wifiClient);
WiFiSSLClient   httpsClient;
WiFiServer      apServer(80);

void setup() {

}

void loop() {
 if (WiFi.status() != WL_CONNECTED) {
   connectWiFi();
 }

 if (!mqttClient.connected()) { 
   if (mqttConnect()) {
     //ok
   } else {
     //handle errors
   }
 }

 mqttClient.poll(); 
}


void connectWiFi() {
 WiFi.disconnect();
 while (WiFi.begin(ssid, password) != WL_CONNECTED) {
   //handling failed attempts 
 }
 sleep(1000);
}  


boolean mqttConnect() {
 while (!mqttClient.connect(broker, port)) {
   //handling failed attempts  
 }
 mqttClient.onMessage(onMessageReceived);
 mqttClient.subscribe(topic, qos);
 if (mqttClient.connected()) {
   return true;
 } else {
   return false;
 }
}


void onMessageReceived(int messageSize) {
 String topic = mqttClient.messageTopic();
 String payload;
 while (mqttClient.available()) {
   char c = mqttClient.read();
   if (c != ' ') {
     payload = payload + c;
   }
 }
 parseAndExecute(payload);
}


void parseAndExecute(String str) {
 //handling hardware, may take several seconds to complete
}

Post the complete program.

What is the point in posting a snippet with what may be the most important piece empty

}
 parseAndExecute(payload);
}


void parseAndExecute(String str) {
 //handling hardware, may take several seconds to complete
}

If you really do want to ignore new messages for several seconds while something else happens then you need to disable the receipt of incoming messages until you are ready. For all I know that may also require changes to the code that is sending the messages - for example maybe it should wait until it receives a request from the Arduino.

...R

Yes, I want to ignore new messages while handling current one but couldn't find how to disable the previously set onMessage() . From what I understand this is the only way to prevent re-entries.

Due to the asynchronous nature of the system we prefer not to go into server side solution.

Posting 1,200 lines of code will not add to anyone's understanding of the problem.

I want to ignore new messages while handling current one

Make handling a message dependant on a boolean being true and set the boolean false when you don't want to handle messages.

UKHeliBob:
Make handling a message dependant on a boolean being true and set the boolean false when you don't want to handle messages.

No, this will not prevent reentering the function set in onMessage().

ninora:
No, this will not prevent reentering the function set in onMessage().

It can if you make it that way.

No, this will not prevent reentering the function set in onMessage().

Then you did something wrong.

bool doSomething = true;

void onMessageReceived(int messageSize)
{
   String topic = mqttClient.messageTopic();
   String payload;
   if(doSomething)
   {
      doSomething = false;
      while (mqttClient.available())
      {
         char c = mqttClient.read();
         if (c != ' ')
         {
            payload = payload + c;
         }
      }
      parseAndExecute(payload);
  }
}

However, you real problem is that you do not understand what you can, and can not do, in a message handler.

//handling hardware, may take several seconds to complete

You can ONLY take "several seconds" to handle each message IF you make CERTAIN that the broker will allow you "several seconds" to complete handling each message.

If you can't, you can't take "several seconds" to handle each message.

Paul,

Motto suggestion: "The art of giving good answer lies in understanding the question."

Your example will prevent executing the code fenced by doSomething but WILL NOT prevent reentering onMessageReceived which is the issue I am trying to solve here.

If what I am looking for do not exists, meaning a way to cancel mqtt.onMessage(), it may be a good idea to implement it in the library.

void onMessageReceived(int messageSize) {
  mqttClient.onMessage(nullptr);
  //
  // do stuff
  //
  mqttClient.onMessage(onMessageReceived);
}

Your example will prevent executing the code fenced by doSomething but WILL NOT prevent reentering onMessageReceived which is the issue I am trying to solve here.

You are trying to solve the wrong problem, then. Having the function called, and taking no time at all to return is NOT a problem.

ninora:
No, this will not prevent reentering the function set in onMessage().

Why not make the onMessage() function very short. It just checks for a variable that says whether it can use or ignore a message. Something like

myOnMessageFunction() {
  if (okToDealWithMessage == true) {
     okToDealWithMessage = false;
     myFunc();
  }
}

...R

Robin2:
Why not make the onMessage() function very short. It just checks for a variable that says whether it can use or ignore a message.

This can be a patch, not a solid solution.

Having no way to prevent reentry we will implement a solution in the server, let it wait for confirmation before sending new message.

ninora:
This can be a patch, not a solid solution.

In what way is it not a solid solution?

...R

Robin2:
In what way is it not a solid solution?

Or Reply #11 for that matter?

Robin2:
Why not make the onMessage() function very short. It just checks for a variable that says whether it can use or ignore a message. Something like

myOnMessageFunction() {

if (okToDealWithMessage == true) {
    okToDealWithMessage = false;
    myFunc();
  }
}




...R

I prefer the guard clause to reduce the amount of nested indentations, especially in slightly longer functions.

myOnMessageFunction() {
  if ( !okToDealWithMessage ) //return immediately if you can't process the message.
    return;

  okToDealWithMessage = false;
  myFunc();
  okToDealWithMessage = true;
}

Jiggy-Ninja:
I prefer the guard clause to reduce the amount of nested indentations, especially in slightly longer functions.

I agree - I just wrote out my suggestion in Reply #13 at short notice.

...R

Looking in another direction...
If I write reentrant/recursive code - I use a local counter to determine the depth of recursion... and simply throw an exception or return if too deep..