espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.62k stars 7.28k forks source link

esp_mqtt_client_enqueue sometimes blocks for 10+ milliseconds (IDFGH-12013) #13078

Open readmodifywrite opened 8 months ago

readmodifywrite commented 8 months ago

Answers checklist.

IDF version.

v5.1-564-g8d2dbd461f

Espressif SoC revision.

ESP32-C3

Operating System used.

Linux

How did you build your project?

Command line with Make

If you are using Windows, please specify command line type.

None

Development Kit.

Custom board

Power Supply used.

USB

What is the expected behavior?

According to the documentation, esp_mqtt_client_enqueue should return immediately.

What is the actual behavior?

esp_mqtt_client_enqueue is sometimes blocking for many milliseconds, sometimes more than 30 ms. This is not a non-blocking API, although the documentation claims it is.

Steps to reproduce.

Time esp_mqtt_client_enqueue with an active connection. Notice how your user thread hangs.

Debug Logs.

No response

More Information.

No response

euripedesrocha commented 8 months ago

Hi @readmodifywrite thanks for reporting, we identified the issue already, but unfortunately it isn't an easy fix at the moment. We plan to attack the problem soon.

readmodifywrite commented 8 months ago

Great to here that! Let me know when you have a possible fix, I'd be happy to test it!

euripedesrocha commented 8 months ago

@readmodifywrite unfortunately it isn't an easy fix, and that is the reason we didn't fix it yet. We need to land some modifications that need extra careful testing and verification. One workaround that you could try on your system is to use esp_mqtt_dispatch_custom_event.

readmodifywrite commented 8 months ago

Are you referring to the workaround here? https://github.com/espressif/esp-mqtt/issues/231

FWIW, I'm not interested in patching ESP-MQTT myself, that's a non-starter.

What if I just replace the entire queuing functionality myself? Can I just shovel messages into a FreeRTOS queue, receive them in another thread, and then just call esp_mqtt_client_publish?

Also, if it is that simple, why would the fix be so complicated? Am I missing something?

readmodifywrite commented 8 months ago

I guess the difference might be that I only need to queue for a single client, but ESP-MQTT needs to handle multiple clients/queues?

euripedesrocha commented 8 months ago

@readmodifywrite the workaround I mentioned was to use esp_mqtt_dispatch_custom_event to send the data to the internal event queue and later process the publish/enqueue in the registered event handler.

The challenge of this relies on the reorganization of the internal data structures to avoid the locks keeping the thread safety and without breaking compatibility. It is feasible but as I mentioned needs extra testing.

readmodifywrite commented 8 months ago

I think for my use case, I can get away with a blocking thread using publish and a queue for the non-blocking thread.

euripedesrocha commented 8 months ago

@readmodifywrite this will work. The solution I proposed uses the resources that are already in place and may save you the extra thread. You might need the queue for the id of messages published in case of QoS > 0.