Hello nice Node-RED peoples,
I have done a bad. I know I have, but I don't know how to not.
So, in an effort to avoid having to learn how to database, I got the idea to just store every incoming MQTT message in a global array; just the current topic and payload. Updates when a new message comes in, overwrites the last payload value per topic.
These are light and switch states, so the payload is usually {"state": true} or {"state": false}, so the data ought to be small. I thought.
My rationale for doing this was that I could then query the current state in code elsewhere. For example, a person has entered the bog. Have they shut the door behind them? They have. Does the distance between the ceiling and the bog seat indicate they are probably sat down? It does. Serious business, then, best start the extractor fan
There I was, so convinced I had been very clever, waltzed away from the keyboard to go and do practical things in the world, and when I came back some hours later, the memory and disc space were maxed, and the spouse was unhappy because nothing was working. To be fair, I was unhappy too.
I run Node-RED in an LXC on Proxmox, with 4GB of RAM and 8GB of drive. I doubled both of these, and watched as they began to fill up over the next few hours. Clearly it's the new code, because when I disable that function, the problem goes away.
It seems, therefore, that I have fundamentally misunderstood how Node-RED manages memory. I don't seem to be updating the global array so much as copying it every time it updates, I think.
There are only 60ish topics, and the array is stable at that size - in other words, it's not just growing and growing.
Here is my stupid function. Please tell me what I am doing wrong. I would prefer to understand this in a way that prevents me from being this wrong again.
If this was a dumb idea from the get-go, I would like to understand why that is, too.
[{"id":"faa407de87fa8f70","type":"function","z":"c8268b7b6089484d","name":"Shove in a global array","func":"var obj = { // Creates thing we're going to store.\n \"topic\": msg.topic,\n \"status\": msg.payload\n};\nvar states = global.get(\"states\") || []; // If the global \"states\" array doesn't exist, return an empty one.\nvar big = states.length; // Is how we'll know if it's empty\nvar found = false;\nif (big == 0){ // It was empty, so we shove a the new thing into it. Now it's not empty. Yay.\n states.push(obj);\n} else {\n let keys = Object.keys(states); // Fine, it's not empty, so first let's check if we've seen this topic before\n for (let i = 0; i < keys.length; i++) {\n var temp = states[i];\n if (obj.topic == temp.topic){ // Hello old friend.\n found = true; // They were lost, but now they are found. But they're vegetarian, let the goat go.\n temp.status = obj.status; // Update the stored payload with the current one.\n break; // annnnnd stop looking.\n }\n };\n if(found == false){ // If we still didn't find this topic, then its obviously unique, just shove the new thing in,\n states.push(obj);\n };\n};\nglobal.set(\"states\", states); // This might be where the mistake is. Is this the mistake? I feel like it is.\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":480,"wires":[[]]},{"id":"5e03e7cd7cf7cdc0","type":"mqtt in","z":"c8268b7b6089484d","name":"","topic":"","qos":"2","datatype":"auto-detect","nl":false,"rap":true,"rh":0,"inputs":0,"x":570,"y":480,"wires":[["faa407de87fa8f70"]]}]
I thank you.