malee
15 May 2025 11:46
1
I am working on a way of gracefully stopping a node-RED instance from running to simply the task of bench marking with clinic.js and auto cannon. To allow for this to happen I initially tried using a call to RED.stop()
in a function node.
When doing so I received a Type error: RED.stop is not a function.
I then tried installing a simple node that just registers an endpoint, the HTML file is just a script tag:
module.exports = function(RED) {
try {
const shutdownEndpointPath = '/my-secret-shutdown-trigger';
RED.httpAdmin.get(shutdownEndpointPath, function(req, res) {
RED.log.info(`Custom shutdown endpoint (${shutdownEndpointPath}) called. Initiating Node-RED shutdown`);
res.status(200).json({message: "Node-RED shutdown sequence initiated"});
setTimeout(() => {
RED.stop();
}, 100);
});
RED.log.info(`Custom shutdown endpoint registered. Access it at [Your Node-RED Admin Root URL]${shutdownEndpointPath}`);
} catch(err) {
RED.log.error("Failed to register custom shutdown endpoint in settings.js " + err.toString());
}
}
Again same Type error.
I am running v4.0.9 of Node-RED on LInux 22.04 with Node v22.15.0 in a docker container.
Hi @malee
Nodes don't have access to the runtime lifecycle apis; they can't stop the runtime directly.
You'd need to go down the embedded route (docs ) as that will give you access to the top level RED
api and control over the full lifecycle.
1 Like
malee
15 May 2025 16:45
3
Hi @knolleary ,
Managed to get a result using autocannon
with the clinic Heap Profiler.
It seems that when autocannon
completes the exit process is graceful enough to allow for the data to be collected and formatted for analysis.
thanks
Matt
1 Like
Could you share your setup with the community?
malee
16 May 2025 09:38
5
Sure no problem, this is the WIP
const http = require("http");
const express = require("express");
const RED = require("node-red");
const app = express();
const server = http.createServer(app);
const settings = {
httpAdminRoot: "/",
httpNodeRoot: "/api",
userDir: "./.node-red-data/",
flowFile: "flows.json",
functionGlobalContext: {},
logging: {
console: {
level: "info",
metrics: false,
audit: false,
},
},
};
RED.init(server, settings);
if (settings.httpAdminRoot) {
app.use(settings.httpAdminRoot, RED.httpAdmin);
}
if (settings.httpNodeRoot) {
app.use(settings.httpNodeRoot, RED.httpNode);
}
const SHUTDOWN_TIMEOUT_MS = 30000;
let shutdownTimer;
function gracefulShutdown() {
console.log("Initiating Node-RED shutdown...");
RED.stop()
.then(() => {
console.log("Node-RED runtime stopped.");
server.close(() => {
console.log("HTTP server closed.");
process.exit(0);
});
})
.catch((err) => {
console.error("Error stopping Node-RED:", err);
process.exit(1);
});
}
const controlApp = express();
const controlServer = http.createServer(controlApp);
const CONTROL_PORT = 8099;
controlApp.get("/shutdown-nodered", (req, res) => {
console.log("Received /shutdown-nodered request.");
res.send("Shutdown signal received. Node-RED will attempt to stop.");
if (shutdownTimer) clearTimeout(shutdownTimer);
gracefulShutdown();
});
controlServer.listen(CONTROL_PORT, () => {
console.log(`Control server listening on http://localhost:${CONTROL_PORT}`);
console.log(
`Call http://localhost:${CONTROL_PORT}/shutdown-nodered to stop Node-RED`
);
});
RED.start()
.then(() => {
const PORT = settings.uiPort || process.env.PORT || 1880;
server.listen(PORT, () => {
console.log(
`Node-RED embedded and running on http://localhost:${PORT}${
settings.httpAdminRoot || "/"
}`
);
RED.log.info(`Node-RED version ${RED.version()} started`);
});
})
.catch((err) => {
console.error("Failed to start Node-RED:", err);
process.exit(1);
});
process.on("SIGINT", () => {
console.log("SIGINT received. Shutting down...");
if (shutdownTimer) clearTimeout(shutdownTimer);
gracefulShutdown();
});
There is no need to use the shutdown server with the clinic Heap Profiler and autocannon
as it shuts down gracefully itself. I have also just found that if I comment out process.exit(0)
and shutdown the Heap Profiler with a SIGINT
via CTRL+C
after calling the shutdown-nodered
endpoint thr Heap Profiler compiles data for visualization after being initialized without autocannon
1 Like
malee
16 May 2025 11:14
6
I have made some adjustments to the initial script and it now works
I found that if you kill the process with the process PID
after node-RED has been stopped then clinic.JS completes its tasks as gracefully as you would want.
Solution appears to be replacing the gracefulShutdown
function with this one:
function gracefulShutdown() {
console.log("Initiating Node-RED shutdown...");
RED.stop()
.then(() => {
console.log("Node-RED runtime stopped.");
server.close(() => {
console.log("HTTP server closed.");
process.kill(process.pid, 'SIGINT');
});
})
.catch((err) => {
console.error("Error stopping Node-RED:", err);
process.exit(1);
});
}
and remove the following:
process.on("SIGINT", () => {
console.log("SIGINT received. Shutting down...");
if (shutdownTimer) clearTimeout(shutdownTimer);
gracefulShutdown();
});
Result!
When for example you run
clinic heapprofiler -- node start-node-red.js
and call the following endpoint to end the process.
curl http://localhost:8099/shutdown-nodered
If for example you run autocannon
then shutdown is automatic
clinic heapprofiler --autocannon [ http://localhost:8080/api/folderlisting -m POST -d 60 ] -- node start-node-red.js
1 Like
system
Closed
30 May 2025 12:55
8
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.