NodeRED crashing due to "Javascript out of heap memory" issue

Hi there. I have been constantly getting "Javascript out of heap memory" error due to which the nodered is crashing, resulting in data loss. I have tried allocating 8gb memory to it with the command:
docker run -it -p 1880:1880 -v node_red_data:/data --name nodered 0--memory=8g -e NODE_OPTIONS="--max-old-space-size=8192" nodered/node-red
But still the issue remains. Please help me resolve the issue.

Thanks in advance!

Node-red by itself will not cause an out of memory error - this is more likely caused by a flow. Are you using loops in your flows for example ?

You should generally allow Node.js to manage its own memory - max-old-space-size should generally not be used.

When you get heap exhaustion, that is most often caused by a memory leak somewhere. Often a transient process that doesn't clear up after itself.

If you can, start by turning off parts of your flows and review memory use as you go along. That may help you identify where it is happeing.

Otherwise, you will need to learn how to run Node-RED in debug mode - thankfully now much easier if you use the node-renode-red-contrib-inspector package.

Less likely, but possible would be trying to keep too much data in-memory such as an unconstrained context variable that keeps growing.

@bakman2 @TotallyInformation Thank you for your response. I would like to know, can the Node-RED crash occur if one of my flows is having some issue but I have disabled it? Also, can the reason be due to using too many function nodes?

The number of function nodes should not matter, the content of the function nodes is more important. What are your flows executing ?

Let me share the function nodes I am using. This is the first one:

// Log the incoming payload for debugging purposes
node.warn("Incoming payload: " + JSON.stringify(msg.payload));

// Check if the payload has a 'data' property that is an array
if (msg.payload.hasOwnProperty("data") && Array.isArray(msg.payload.data)) {
// Get the value at index 0 of the 'data' array and convert it to 0 or 1
var valueAtZero = msg.payload.data[0] || false; // Default to false if undefined
msg.payload = valueAtZero ? 1 : 0;
} else {
// Handle the case where 'data' property does not exist or is not an array
node.error("'data' property is missing or not an array in the payload", msg);
// Set msg.payload to undefined or handle error case as needed
msg.payload = undefined;
}

// Return the modified message
return msg;

The second one:
// Assuming msg.payload contains your data
// Modify the payload to add "START" as a field name
msg.payload = {
START: msg.payload
};

return msg;

I have multiple similar nodes.

what is in the payloads? I see msg.payload.data[x] suggesting this is an array of data.

How many function nodes? how often are they called? what size data is pushed through them? Are you storing any data in context?

The system processes data through approximately 800-1000 function nodes, handling structured payloads where msg.payload.data[x] suggests an array of data elements. These function nodes are called frequently, likely at regular intervals, to process and transform incoming data. The payload sizes vary depending on the specific data source and processing requirements. Multiple flows are involved, including both active and disabled ones, interacting with different data sources, including InfluxDB instances and Modbus clients. Some data may be stored in context for temporary processing or reference across executions.

It is possible but less likely. Remember that each node package is loaded when Node-RED starts so a bunch of work is done and data potentially created. There is then a 2nd tranche of work as each node in your flows is loaded. Generally, that 2nd phase is a more likely place for things to start going wrong. The final phase happens when a node instance receives a message and because this is likely to happen very often, a poorly coded function there can really mess things up.

When you disable a node or a flow with nodes, phases 2 and 3 shouldn't be run.

As bakman2 says, not really about the number, more what they are doing. Each function node runs a VM which isolates the code so is generally fairly safe. But it is certainly possible even there to mess things up.

Wow, ok that IS a lot!

It feels like you should be looking at how you can simplify things. Also, with that number of nodes, take care with debug nodes and places in your flows where you have >1 wire connected to the output of a node. That's because having multiple wires on an output causes Node-RED to have to CLONE the output messages which is a relatively heavy task.

Can't standard nodes have memory leaks too? Like join and incomplete groups when not sending reset msg?

How do I know if there is a memory leak?

Usually you know when getting out of memory error :stuck_out_tongue:

1 Like

Is that true if the wire goes to a disabled node?
What about a debug node whose output is "turned off"?

Does this Node-red instance interact directly with database and Modbus clients?
It might be worth moving data acquisition to a separate NR instance on another machine and use MQTT to forward it to be processed.

What hardware are you running on?

Have you experimented with the same Node-red flows but not under Docker? (I have no reason at all to think Docker might be at fault, it's just one more factor to consider).

[This thread](This thread [Question about context and RAM - #2 by Paul-Reed]) discusses some ways to monitor Node-red memory usage.

Those are great questions and I also have them. I'm afraid I've never quite gotten around to actually testing the answers. Maybe Steve knows?

1 Like

I don't know. Not an area I've touched. But logically, I suspect there is NOT a dedicated piece of code that detects if the thing on the end of the wire is of type debug with it's button depressed. So in short. I suspect there will still be duplication.

Without trawling the code base, off the top of my head, a possible way to test could be to add a symbol to the msg and feed it to a function (that prints the symbol) and to a debug node with output disabled. (Symbols are unique and immutable, even if they have the same description)

For example, in regular js/node...

const marker = Symbol('uniqueMarker');

function markObject(obj) {
  if (typeof obj === 'object' && obj !== null) {
    obj[marker] = true;
  }
}

function isSameReference(obj) {
  return obj?.[marker] === true;
}

// Usage:
const original = {};
markObject(original);

function testObject(input) {
  if (isSameReference(input)) {
    console.log('Same reference');
  } else {
    console.log('Cloned or different object');
  }
}

testObject(original); // Same reference
testObject({ ...original }); // Cloned or different object

Maybe could be adapted to node-red flow?

Hi there. I am sharing my flow json, maybe that would help identify the issue?:

[
    {
        "id": "72206b283865743e",
        "type": "tab",
        "label": "Knitting-150[18]",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "fef411574e293b72",
        "type": "function",
        "z": "72206b283865743e",
        "name": "0/1 (True/False)",
        "func": "// Log the incoming payload for debugging purposes\nnode.warn(\"Incoming payload: \" + JSON.stringify(msg.payload));\n\n// Check if the payload has a 'data' property that is an array\nif (msg.payload.hasOwnProperty(\"data\") && Array.isArray(msg.payload.data)) {\n    // Get the value at index 0 of the 'data' array and convert it to 0 or 1\n    var valueAtZero = msg.payload.data[0] || false; // Default to false if undefined\n    msg.payload = valueAtZero ? 1 : 0;\n} else {\n    // Handle the case where 'data' property does not exist or is not an array\n    node.error(\"'data' property is missing or not an array in the payload\", msg);\n    // Set msg.payload to undefined or handle error case as needed\n    msg.payload = undefined;\n}\n\n// Return the modified message\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 140,
        "y": 160,
        "wires": [
            [
                "49e09a5b88378a7d"
            ]
        ]
    },
    {
        "id": "3c0829a71190a046",
        "type": "function",
        "z": "72206b283865743e",
        "name": "0/1 (True/False)",
        "func": "// Log the incoming payload for debugging purposes\nnode.warn(\"Incoming payload: \" + JSON.stringify(msg.payload));\n\n// Check if the payload has a 'data' property that is an array\nif (msg.payload.hasOwnProperty(\"data\") && Array.isArray(msg.payload.data)) {\n    // Get the value at index 0 of the 'data' array and convert it to 0 or 1\n    var valueAtZero = msg.payload.data[0] || false; // Default to false if undefined\n    msg.payload = valueAtZero ? 1 : 0;\n} else {\n    // Handle the case where 'data' property does not exist or is not an array\n    node.error(\"'data' property is missing or not an array in the payload\", msg);\n    // Set msg.payload to undefined or handle error case as needed\n    msg.payload = undefined;\n}\n\n// Return the modified message\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 140,
        "y": 280,
        "wires": [
            [
                "c12cffdd82ef039c"
            ]
        ]
    },
    {
        "id": "034dc427145241e5",
        "type": "function",
        "z": "72206b283865743e",
        "name": "0/1 (True/False)",
        "func": "// Log the incoming payload for debugging purposes\nnode.warn(\"Incoming payload: \" + JSON.stringify(msg.payload));\n\n// Check if the payload has a 'data' property that is an array\nif (msg.payload.hasOwnProperty(\"data\") && Array.isArray(msg.payload.data)) {\n    // Get the value at index 0 of the 'data' array and convert it to 0 or 1\n    var valueAtZero = msg.payload.data[0] || false; // Default to false if undefined\n    msg.payload = valueAtZero ? 1 : 0;\n} else {\n    // Handle the case where 'data' property does not exist or is not an array\n    node.error(\"'data' property is missing or not an array in the payload\", msg);\n    // Set msg.payload to undefined or handle error case as needed\n    msg.payload = undefined;\n}\n\n// Return the modified message\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 600,
        "y": 180,
        "wires": [
            [
                "55be600b01caae1a"
            ]
        ]
    },
    {
        "id": "1b433f8ce505b22e",
        "type": "function",
        "z": "72206b283865743e",
        "name": "0/1 (True/False)",
        "func": "// Log the incoming payload for debugging purposes\nnode.warn(\"Incoming payload: \" + JSON.stringify(msg.payload));\n\n// Check if the payload has a 'data' property that is an array\nif (msg.payload.hasOwnProperty(\"data\") && Array.isArray(msg.payload.data)) {\n    // Get the value at index 0 of the 'data' array and convert it to 0 or 1\n    var valueAtZero = msg.payload.data[0] || false; // Default to false if undefined\n    msg.payload = valueAtZero ? 1 : 0;\n} else {\n    // Handle the case where 'data' property does not exist or is not an array\n    node.error(\"'data' property is missing or not an array in the payload\", msg);\n    // Set msg.payload to undefined or handle error case as needed\n    msg.payload = undefined;\n}\n\n// Return the modified message\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 600,
        "y": 280,
        "wires": [
            [
                "42d2925d35e9b3f3"
            ]
        ]
    },
    {
        "id": "0db5ba55f895da01",
        "type": "function",
        "z": "72206b283865743e",
        "name": "0/1 (True/False)",
        "func": "// Log the incoming payload for debugging purposes\nnode.warn(\"Incoming payload: \" + JSON.stringify(msg.payload));\n\n// Check if the payload has a 'data' property that is an array\nif (msg.payload.hasOwnProperty(\"data\") && Array.isArray(msg.payload.data)) {\n    // Get the value at index 0 of the 'data' array and convert it to 0 or 1\n    var valueAtZero = msg.payload.data[0] || false; // Default to false if undefined\n    msg.payload = valueAtZero ? 1 : 0;\n} else {\n    // Handle the case where 'data' property does not exist or is not an array\n    node.error(\"'data' property is missing or not an array in the payload\", msg);\n    // Set msg.payload to undefined or handle error case as needed\n    msg.payload = undefined;\n}\n\n// Return the modified message\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1060,
        "y": 180,
        "wires": [
            [
                "45aef32ceed04997"
            ]
        ]
    },
    {
        "id": "38faaeb179e7335f",
        "type": "function",
        "z": "72206b283865743e",
        "name": "0/1 (True/False)",
        "func": "// Log the incoming payload for debugging purposes\nnode.warn(\"Incoming payload: \" + JSON.stringify(msg.payload));\n\n// Check if the payload has a 'data' property that is an array\nif (msg.payload.hasOwnProperty(\"data\") && Array.isArray(msg.payload.data)) {\n    // Get the value at index 0 of the 'data' array and convert it to 0 or 1\n    var valueAtZero = msg.payload.data[0] || false; // Default to false if undefined\n    msg.payload = valueAtZero ? 1 : 0;\n} else {\n    // Handle the case where 'data' property does not exist or is not an array\n    node.error(\"'data' property is missing or not an array in the payload\", msg);\n    // Set msg.payload to undefined or handle error case as needed\n    msg.payload = undefined;\n}\n\n// Return the modified message\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1060,
        "y": 280,
        "wires": [
            [
                "186fea92d08d0b27"
            ]
        ]
    },
    {
        "id": "9dcc4eaf2ae0e9db",
        "type": "function",
        "z": "72206b283865743e",
        "name": "RPM",
        "func": "// Access the array within the payload's 'data' property\nif (msg.payload && Array.isArray(msg.payload.data) && msg.payload.data.length > 0) {\n    msg.payload = msg.payload.data[0]; // Extract the first element\n} else {\n    msg.payload = undefined; // Handle invalid payloads\n}\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1470,
        "y": 180,
        "wires": [
            [
                "4fa7f6b7afd5752f"
            ]
        ]
    },
    {
        "id": "0fc2cd7d066deb78",
        "type": "function",
        "z": "72206b283865743e",
        "name": "RPM",
        "func": "// Access the array within the payload's 'data' property\nif (msg.payload && Array.isArray(msg.payload.data) && msg.payload.data.length > 0) {\n    msg.payload = msg.payload.data[0]; // Extract the first element\n} else {\n    msg.payload = undefined; // Handle invalid payloads\n}\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1470,
        "y": 280,
        "wires": [
            [
                "e1536e1e544b6ba0"
            ]
        ]
    },
    {
        "id": "49e09a5b88378a7d",
        "type": "function",
        "z": "72206b283865743e",
        "name": "START",
        "func": "// Assuming msg.payload contains your data\n// Modify the payload to add \"START\" as a field name\nmsg.payload = {\n    START: msg.payload\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 140,
        "y": 160,
        "wires": [
            [
                "6f228ae9ee638864"
            ]
        ]
    },
    {
        "id": "c12cffdd82ef039c",
        "type": "function",
        "z": "72206b283865743e",
        "name": "START",
        "func": "// Assuming msg.payload contains your data\n// Modify the payload to add \"START\" as a field name\nmsg.payload = {\n    START: msg.payload\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 140,
        "y": 280,
        "wires": [
            [
                "bfe91caa1489cd83"
            ]
        ]
    },
    {
        "id": "55be600b01caae1a",
        "type": "function",
        "z": "72206b283865743e",
        "name": "YARN",
        "func": "// Assuming msg.payload contains your data\n// Modify the payload to add \"START\" as a field name\nmsg.payload = {\n    YARN: msg.payload\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 590,
        "y": 180,
        "wires": [
            [
                "6f228ae9ee638864"
            ]
        ]
    },
    {
        "id": "42d2925d35e9b3f3",
        "type": "function",
        "z": "72206b283865743e",
        "name": "YARN",
        "func": "// Assuming msg.payload contains your data\n// Modify the payload to add \"START\" as a field name\nmsg.payload = {\n    YARN: msg.payload\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 590,
        "y": 280,
        "wires": [
            [
                "bfe91caa1489cd83"
            ]
        ]
    },
    {
        "id": "45aef32ceed04997",
        "type": "function",
        "z": "72206b283865743e",
        "name": "NEEDLE",
        "func": "// Assuming msg.payload contains your data\n// Modify the payload to add \"START\" as a field name\nmsg.payload = {\n    NEEDLE: msg.payload\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1060,
        "y": 180,
        "wires": [
            [
                "6f228ae9ee638864"
            ]
        ]
    },
    {
        "id": "186fea92d08d0b27",
        "type": "function",
        "z": "72206b283865743e",
        "name": "NEEDLE",
        "func": "// Assuming msg.payload contains your data\n// Modify the payload to add \"START\" as a field name\nmsg.payload = {\n    NEEDLE: msg.payload\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1060,
        "y": 280,
        "wires": [
            [
                "bfe91caa1489cd83"
            ]
        ]
    },
    {
        "id": "4fa7f6b7afd5752f",
        "type": "function",
        "z": "72206b283865743e",
        "name": "RPM Field",
        "func": "// Assuming msg.payload contains your data\n// Modify the payload to add \"START\" as a field name\nmsg.payload = {\n    RPM : msg.payload\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1510,
        "y": 200,
        "wires": [
            [
                "6f228ae9ee638864"
            ]
        ]
    },
    {
        "id": "e1536e1e544b6ba0",
        "type": "function",
        "z": "72206b283865743e",
        "name": "RPM Field",
        "func": "// Assuming msg.payload contains your data\n// Modify the payload to add \"START\" as a field name\nmsg.payload = {\n    RPM : msg.payload\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1510,
        "y": 300,
        "wires": [
            [
                "bfe91caa1489cd83"
            ]
        ]
    },
    {
        "id": "6f228ae9ee638864",
        "type": "influxdb out",
        "z": "72206b283865743e",
        "influxdb": "b9d9fff5425e5aa3",
        "name": "",
        "measurement": "FRIB100",
        "precision": "",
        "retentionPolicy": "",
        "database": "database",
        "precisionV18FluxV20": "ms",
        "retentionPolicyV18Flux": "",
        "org": "test",
        "bucket": "Knitting-150",
        "x": 2110,
        "y": 120,
        "wires": []
    },
    {
        "id": "bfe91caa1489cd83",
        "type": "influxdb out",
        "z": "72206b283865743e",
        "influxdb": "b9d9fff5425e5aa3",
        "name": "",
        "measurement": "FRIB101",
        "precision": "",
        "retentionPolicy": "",
        "database": "database",
        "precisionV18FluxV20": "ms",
        "retentionPolicyV18Flux": "",
        "org": "TYNOR",
        "bucket": "Knitting-150",
        "x": 2110,
        "y": 240,
        "wires": []
    },
    {
        "id": "530b1dec92c7eee0",
        "type": "influxdb out",
        "z": "72206b283865743e",
        "influxdb": "b9d9fff5425e5aa3",
        "name": "",
        "measurement": "FRIB102",
        "precision": "",
        "retentionPolicy": "",
        "database": "database",
        "precisionV18FluxV20": "ms",
        "retentionPolicyV18Flux": "",
        "org": "TYNOR",
        "bucket": "Knitting-150",
        "x": 2110,
        "y": 340,
        "wires": []
    },
    {
        "id": "981592084687e402",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 390,
        "y": 120,
        "wires": []
    },
    {
        "id": "45d55d079432478e",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 850,
        "y": 120,
        "wires": []
    },
    {
        "id": "7ad5750b04c47dc8",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 1270,
        "y": 120,
        "wires": []
    },
    {
        "id": "2fbe8479069f0ad2",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 1730,
        "y": 120,
        "wires": []
    },
    {
        "id": "dec5ae7950797f91",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 390,
        "y": 240,
        "wires": []
    },
    {
        "id": "a3b01e21ddbce8e7",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 850,
        "y": 240,
        "wires": []
    },
    {
        "id": "bf88ed0d0d8b9df0",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 1270,
        "y": 240,
        "wires": []
    },
    {
        "id": "3b793efc3d3c22ad",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 1730,
        "y": 240,
        "wires": []
    },
    {
        "id": "7c57c56768dbb00d",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 390,
        "y": 340,
        "wires": []
    },
    {
        "id": "6bf993e1ca7bd102",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 850,
        "y": 340,
        "wires": []
    },
    {
        "id": "fd6d343281a179de",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 1270,
        "y": 340,
        "wires": []
    },
    {
        "id": "108f9c7d5a57243a",
        "type": "modbus-response",
        "z": "72206b283865743e",
        "name": "",
        "registerShowMax": 20,
        "x": 1730,
        "y": 340,
        "wires": []
    },
    {
        "id": "7a56c500931d8b24",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB100",
        "topic": "RUN",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "0095",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 140,
        "y": 100,
        "wires": [
            [],
            [
                "981592084687e402",
                "fef411574e293b72"
            ]
        ]
    },
    {
        "id": "9806d9e5e19cf103",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB100",
        "topic": "YARN",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "2095",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 600,
        "y": 100,
        "wires": [
            [],
            [
                "45d55d079432478e",
                "034dc427145241e5"
            ]
        ]
    },
    {
        "id": "d3ac6ab3ac65a727",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB100",
        "topic": "NEEDLE",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "3095",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 1060,
        "y": 100,
        "wires": [
            [],
            [
                "7ad5750b04c47dc8",
                "0db5ba55f895da01"
            ]
        ]
    },
    {
        "id": "234ab9e6c8829ce4",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB100",
        "topic": "RPM",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "HoldingRegister",
        "adr": "0095",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 1480,
        "y": 100,
        "wires": [
            [],
            [
                "2fbe8479069f0ad2",
                "9dcc4eaf2ae0e9db"
            ]
        ]
    },
    {
        "id": "49d84aa47a05e024",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB101",
        "topic": "RUN",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "0096",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 140,
        "y": 220,
        "wires": [
            [],
            [
                "dec5ae7950797f91",
                "3c0829a71190a046"
            ]
        ]
    },
    {
        "id": "12a72fdd886cb02e",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB101",
        "topic": "YARN",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "2096",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 600,
        "y": 220,
        "wires": [
            [],
            [
                "a3b01e21ddbce8e7",
                "1b433f8ce505b22e"
            ]
        ]
    },
    {
        "id": "5d09dd380ff1dbd8",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB101",
        "topic": "NEEDLE",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "3096",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 1060,
        "y": 220,
        "wires": [
            [],
            [
                "bf88ed0d0d8b9df0",
                "38faaeb179e7335f"
            ]
        ]
    },
    {
        "id": "c973090a077b4655",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB101",
        "topic": "RPM",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "HoldingRegister",
        "adr": "0096",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 1480,
        "y": 220,
        "wires": [
            [],
            [
                "3b793efc3d3c22ad",
                "0fc2cd7d066deb78"
            ]
        ]
    },
    {
        "id": "bdd9fadca3d71b26",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB102",
        "topic": "RUN",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "0097",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 140,
        "y": 320,
        "wires": [
            [],
            [
                "7c57c56768dbb00d"
            ]
        ]
    },
    {
        "id": "9d3c4fce2c5b1347",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB102",
        "topic": "YARN",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "2097",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 600,
        "y": 320,
        "wires": [
            [],
            [
                "6bf993e1ca7bd102"
            ]
        ]
    },
    {
        "id": "0782bd87fd81ffc9",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB102",
        "topic": "NEEDLE",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "Coil",
        "adr": "3097",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 1060,
        "y": 320,
        "wires": [
            [],
            [
                "fd6d343281a179de"
            ]
        ]
    },
    {
        "id": "b820c017e484def6",
        "type": "modbus-read",
        "z": "72206b283865743e",
        "name": "FRIB102",
        "topic": "RPM",
        "showStatusActivities": false,
        "logIOActivities": false,
        "showErrors": false,
        "showWarnings": true,
        "unitid": "1",
        "dataType": "HoldingRegister",
        "adr": "0097",
        "quantity": "1",
        "rate": "30",
        "rateUnit": "s",
        "delayOnStart": false,
        "startDelayTime": "",
        "server": "0524ea2fd47ca0d4",
        "useIOFile": false,
        "ioFile": "",
        "useIOForPayload": false,
        "emptyMsgOnFail": false,
        "x": 1480,
        "y": 320,
        "wires": [
            [],
            [
                "108f9c7d5a57243a"
            ]
        ]
    },
    {
        "id": "b9d9fff5425e5aa3",
        "type": "influxdb",
        "z": "72206b283865743e",
        "hostname": "127.0.0.1",
        "port": "8086",
        "protocol": "http",
        "database": "database",
        "name": "",
        "usetls": false,
        "tls": "",
        "influxdbVersion": "2.0",
        "url": "http://localhost:8086/",
        "timeout": "10",
        "rejectUnauthorized": true
    },
    {
        "id": "0524ea2fd47ca0d4",
        "type": "modbus-client",
        "name": "Knitting [150]",
        "clienttype": "tcp",
        "bufferCommands": true,
        "stateLogEnabled": false,
        "queueLogEnabled": false,
        "failureLogEnabled": true,
        "tcpHost": "192.168.178.150",
        "tcpPort": "502",
        "tcpType": "TCP-RTU-BUFFERED",
        "serialPort": "/dev/ttyUSB",
        "serialType": "RTU-BUFFERD",
        "serialBaudrate": "9600",
        "serialDatabits": "8",
        "serialStopbits": "1",
        "serialParity": "none",
        "serialConnectionDelay": "100",
        "serialAsciiResponseStartDelimiter": "0x3A",
        "unit_id": 1,
        "commandDelay": 1,
        "clientTimeout": 1000,
        "reconnectOnTimeout": true,
        "reconnectTimeout": 2000,
        "parallelUnitIdsAllowed": true,
        "showWarnings": true,
        "showLogs": true
    }
]

You have a large number of double function nodes one after the other. Each requires some setup time, not much but a lot of the nodes are identical. I'd simplify that even if it means some code duplication. I might also reduce the amount of error checking if you can rely on the structure of incoming modbus messages (I don't use modbus).

Similarly, you have a lot of double output wires. Put the function node as the only connection and use the output from the fn node to trigger the response unless that output will take some time to appear, in which case, set the fn node to have TWO outputs, use one to trigger the modbus response and the other for other downstream activities. This will avoid the need for Node-RED to have to clone all of the messages.

You might also consider only using a single InfluxDB output node. Typically, I use a link-out/link-in arrangement with a single node. Not sure that is any more efficient but it can help make sure your outputs are consistent and you could add a small data validation flow if needed. For example, I typically validate InfluxDB outputs to ensure that any values (fields) are NUMBERS and other things like tags and measures contain something sensible.

Notice how I've used what I've suggested above to have 2 outputs from the function so that message cloning doesn't happen.

You might also similarly be able to de-duplicate modbus outputs - but as I don't use it, not sure.

I hope you dont take this the wrong way but from what i see, the flow you have posted is inextensible, unmaintainable and generally the opposite of a good design for data collection. TBH, I am not surprised it you are having issues! I hope you take what I write and the article I link to as a bunch of ideas to improve your situation.


The flow you have posted is obviously just a small section (as earlier you said there were "800-1000 function nodes"). That leads me to believe the rest of your flow is a continuation of the same pattern.

For starters, you are reading individual bits and values - this is both highly inefficient and will result in inconsistent data. I urge you to read (and re-read it until you understand) this document to get a better understanding of why I said the things above: Modernize your legacy industrial data. Part 2. • FlowFuse

Here are some areas I suggest you look at for how you could improve this:

  • Use the modbus getter nodes to sequence your requests (NOT do them all on the same 30 mark - the comms will be too slow resulting in back pressure and eventual crashes)
    • FYI, they will NEVER occur at the same time (comms will be transmitted and received in a serial manor regardless of setting them all to 30s)
  • Group nearby read requests into 1 read that does them all at once.
    • e.g. dont just read single coils 95,96,97,98,99 etc. Read them all in one getter
    • This will reduce back pressure and improve data integrity/consistency
  • Stop doing things like node.warn("Incoming payload: " + JSON.stringify(msg.payload)); in EVERY function.
    • This is wasteful and WILL slow everything down and probably add to the back pressure and crashing
  • Use link-call to reduce duplication
    • e.g. remove EVERY duplicated function, and instead, create a subroutine to a single version of the function using link-call
  • Use change nodes for simple things like updating the payload.

I estimate you could reduce this from 1000s of nodes to ~ 100 or 200 nodes, while making it more maintainable, extensible, reliable and as a bonus, improve data integrity/consistency.

Good luck.

3 Likes

Thank you everyone for your support and suggestions. Will try to implement them. I believe this should work fine.