如何实现通过/etc/init.d脚本正常停止作为服务运行的Node.js服务器
kill/killall Problem Statement
I've set up a small Node.js server as a boot service using an
/etc/init.d/lightserverscript. Currently, thestopaction is empty, and I want to be able to run/etc/init.d/lightserver stopto shut down the server properly without usingkillorkillallcommands. Here's my current init.d script:# Actions case "$1" in start) # START /usr/bin/lightserver ;; stop) # STOP ;; restart) # RESTART ;; esac exit 0And my Node.js server code:
var i = 0; var connect = require('connect'); var sleep = require('sleep'); var exec = require('child_process').exec; var j = 1; var server = connect(). use(function(req, res) { i++; res.write('Hello World! ' + i); res.end(); let code = 83028 + j; j = 1 - j; exec("./433Utils/RPi_utils/codesend " + code, function(error, stdout, stderr) { console.log(stdout); }); }).listen(64084); console.log("Server has started and is listening to http://localhost:64084/");
Solution
Great question! The cleanest way to handle this without kill/killall is to add a local-only shutdown endpoint to your Node.js server, then update the init.d script to trigger this endpoint via a simple HTTP request. Here's how to do it step by step:
Step 1: Update Your Node.js Server Code
Add a dedicated middleware to handle shutdown requests, restricted to localhost for security. We'll use server.close() to gracefully stop accepting new connections and wait for in-progress requests to finish before exiting:
var i = 0; var connect = require('connect'); var sleep = require('sleep'); var exec = require('child_process').exec; var j = 1; var server = connect() // Shutdown handler (must come first to catch the /stop request) .use(function(req, res, next) { // Allow only localhost to trigger shutdown (covers IPv4 and IPv6) const isLocal = req.connection.remoteAddress === '127.0.0.1' || req.connection.remoteAddress === '::1'; if (req.url === '/stop' && isLocal) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Server is shutting down gracefully...'); // Close the server and exit once all connections are done server.close(function() { console.log('Server stopped successfully'); process.exit(0); }); return; } next(); // Pass regular requests to your main handler }) .use(function(req, res) { i++; res.write('Hello World! ' + i); res.end(); let code = 83028 + j; j = 1 - j; exec("./433Utils/RPi_utils/codesend " + code, function(error, stdout, stderr) { console.log(stdout); }); }) .listen(64084); console.log("Server has started and is listening to http://localhost:64084/");
Step 2: Update Your init.d Script
Modify the stop block to call the /stop endpoint using curl (if curl isn't installed, use wget as an alternative):
# Actions case "$1" in start) # START /usr/bin/lightserver ;; stop) # STOP # Trigger shutdown via local HTTP request curl -s http://localhost:64084/stop > /dev/null # Uncomment below if curl isn't available: # wget -q -O - http://localhost:64084/stop > /dev/null ;; restart) # RESTART $0 stop sleep 2 # Give the server time to finish ongoing requests $0 start ;; esac exit 0
Why This Works
- Security: The
/stopendpoint is locked to localhost, so external clients can't shut down your server accidentally or maliciously. - Graceful Shutdown:
server.close()ensures all active requests are completed before the server exits, avoiding broken connections or incomplete operations. - No Kill Commands: The init.d script uses a standard HTTP request instead of low-level process signals, meeting your requirement perfectly.
内容的提问来源于stack exchange,提问作者olek07

