A couple of recent discussions have brought this into question for me.
I’m specifically thinking about how it is/should be implemented in emonHub but I now wonder if this is actually a more global question. Since I do not regularly use MQTT for various reasons, it might just be that I’m over looking something or maybe there is an issue, but it can be easily overcome.
The posts I refer to are the “Mqtt_input service high memory usage” thread that got me thinking about MQTT QoS and what that means to the route to emoncms. The other post was “Data not logged locally” which made me question the value of the QoS 2 settings and therefore question the suitability of using MQTT to post to emoncms with the current emoncms implementation.
When MQTT is published with a QOS level of 2 “exactly once” it involves buffering the data until receipt is confirmed (twice per connection) and since all MQTT involves 2 connections, 1 to the broker and 1 from the broker. What is unclear to me is what is happening with the queue(s). I did find a blog post that says the queue is “FIFO” but that isn’t official documentation.
For now I will assume that to be the case, it’s what I would expect or at least hope for. If the buffered messages do not get released in order once a connection is re-established, that raises another question around the fact that emoncms can only post data in chronological order, this is more so with the “buffered-write” implementation of the low-write mode of emoncms, but because the “buffered-write” mode makes it so difficult to insert data and the low-write mode is essential to the widely used sdcard operation of the emonSD, the insert function’s and api’s do not get developed, so essentially it would apply to all emoncms installs.
The main concern is whether the benifit of QoS 2 is being felt in emoncms, or is it just adding extra processing and slowing the connection down that much that it creates a queue that is unlikely to reach it’s destination.
From what I understand for the FIFO buffer and therefore QoS 2 to work there must be a solid connection that never disconnects (when there is a queue) or the connection between emoncms and the broker must be made “persistent” (see Persistent Session and Queuing Messages - MQTT Essentials: Part 7).
To create a “persistent” MQTT connection the client must supply a client id so that the buffered queue can be repatriated with the correct client. Ordinarily it seems that the default connection method is a “clean” session, which basically tells the broker the new connection is not interested in any previously queued data and that once disconnected, it will not want any data queued until it reconnects. This undermines the intention of using QoS 2 (or even 1) in emoncms applications.
Looking at the docs for the MQTT lib used in emoncms, it seems the constructor needs to be called with a client ID and cleanSession = false
(see Mosquitto\Client — Mosquitto-PHP 0.4.0 documentation).
Currently emoncms constucts a MQTT client with no parameters
So each time it disconnects and reconnects it is assigned a new random Client ID by the broker, a null/omitted client ID implies a cleanSession = true
so no queued data will be passed on re-connection. Essentially, every time there is a dis-connect and reconnect emoncms is starting a fresh connection, even when there is queued data for the taking, emoncms will not receive that data. QoS 2, in this instance doesn’t persist a break in the connection, no matter how short or prolonged it is. Unfortunately, emoncms see’s a huge number of reconnects so I assume there is little or no queued data making it to emoncms.
I believe that we should be at least supplying a client id parameter in the mqtt client constructor, the cleanSession = false
might be implied by supplying the Client ID, might be better to explicitly set it false
anyway.
I suggest we (currently) use the write apikey of the first user, this will currently work as only the first user has mqtt inputs capability in emoncms. We don’t want a hardcoded client id incase more than one emoncms instance is connected to any one broker, but when the mqtt_input becomes multi-user, we do not want this Client id to be per user, so maybe we need a unique ref for each emoncms (in settings.php?), or we can continue to use the apikey of “the admin”, assuming only one admin user.
I have submitted a PR to the emoncms repo for consideration, but I have not tested it, it is predominantly to get a discussion going. But if anyone feels like trying it out, please do, we can devise a test to determine if it works by taking emoncms offline for a few minutes whilst a queue builds up in the broker and then restart emoncms to see if the data is complete, both with and without the “client id”.
Can anyone confirm or disprove my ramblings?