-
Notifications
You must be signed in to change notification settings - Fork 258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature request: Separate locking of outbox (IDFGH-7921) #231
Comments
Hi @someburner, after some work in this issue it proved to be harder than originally expected. I'll keep this open, since the feature is something we may add in the future. |
Thanks! And yes I still think this would be a good feature. For anyone else needing this functionality, here is a patch (on an older master) I have done to achieve (what I believe to be) a safe and mostly non blocking approach with the current state of the repo. And perhaps these will help inform @euripedesrocha about the intended use case for such a feature. To recap: In my application I must limit the number of in-flight QoS1 messages to 1 in order to achieve in-order reception at the broker. MQTT by default does not guarantee order of QoS1, but capping number of in-flight messages is a feature of many client libraries. QoS2 is far too much overhead. And here's what I do: esp-mqtt changes
user changesBasically it is just a thread-safety layer between esp-mqtt client callbacks and user code. Honestly, it's quite a lot of work, so I will just describe an overview of what has to be done, and if anyone wants more detail feel free to comment.
So instead of enqueuing directly with a call the client, I create an If I want to do a QoS1 publish, in the external user thread I increment a TLDRIt's ton of work and overhead if you want non-blocking interaction with That said, I have been testing with this approach for a long time and it appears to work well, so at least there's that. |
@someburner thanks for the feedback, I'll look into the control of in flight messages, and if it should be added as a general option to esp-mqtt. I think that for this particular problem, the solution would be to have a custom outbox controlling the number of QoS1 messages would be a simpler solution. In the latest master, we changed the internal struct for the outbox in a way that I believe it's easier to achieve your goal. |
I believe regardless of outbox being used, there is still the issue of API locks, no? In my case I can't block for very much time at all trying to acquire a lock that is being held by esp-mqtt thread. The internal structure of the outbox is a rather minor issue. I looked at the commits and don't see anything that looks like it might result in less blocking or help with accessing shared resources better. Is there something I'm missing?
Having some built-in functionality for this is only "nice to have" (and should be rather simple IMO). The real issue is being able to know, from another thread, with little to no blocking, what the status of the messages in the outbox are. Iterating over a short linked list should be pretty fast. But because esp-mqtt uses one big mutex for just about everything, it's hard to make predictions about access times with the APIs. I will say the event loop does work quite well for these sorts of things, but it just feels really messy to have to do things this way. When I get some time I will make more of an effort to get acquainted with the code and see if I can come up with any alternatives. |
Hi @someburner, regarding the issues with API locks you are correct, we have issues that we'll work to fix in the near future. At the moment, the solution using the event loop is the way to go. |
As discussed in #230, there are a variety of situations where having separate locks for outbox operations would be desirable.
In the case of
esp_mqtt_client_enqueue
, if the client is locked for extended periods of time due to waiting onesp_transport_write
/ network timeout, new messages cannot be enqueued quickly from an external task when locks are enabled. A suitable workaround was discussed, but is a bit ugly from a user implementation perspective (e.g. having to define a message container type, alloc, dealloc, implement user events). Having a separate lock that for outbox for msg enqueue/dequeue would result in something that is much closer to a non-blocking API.As discussed in this comment, having a separate outbox lock would allow for the user to implement additional outbox logic such as limiting the number of in-flight messages, checking if a certain
msg_id
was delivered yet, etc.On first glance it seems this might be tricky to implement, since
outbox_enqueue
,outbox_set_pending
, etc are often referencingpending_msg_id
.But thinking about it more, all of the outbox APIs are already pretty self-contained, and enqueueing new messages would really only need to know about
connection->last_message_id
which could be moved to the outbox handle. Then perhaps if the outbox was also used for qos0 messages, it would be possible to callmqtt_client_enqueue_priv
without necessarily needing to lock the client, since it appears the values are just assigned toclient->mqtt_state
, and then copied back over inmqtt_enqueue
.The caveats I see are
mqtt_resend_queued
uses a dequeued outbox item, which might cause issues. And also not sure how about logic around fragmented messages. It might be easier to make it so thatesp_mqtt_client_enqueue
does not usemqtt_client_enqueue_priv
and instead just creates aoutbox_message_t
and callsoutbox_enqueue
.The text was updated successfully, but these errors were encountered: