给定一个在变量(即内存中状态和方法的集合)中定义应用程序的
index.js
脚本,您将如何确保运行脚本的调用在应用程序的现有实例上运行,而不是只是创建新实例吗?
例如,考虑这个仅定义计数器的应用程序,以及启动增量间隔、暂停间隔和读取当前计数的方法:
// ####################################################
// Define app
// ####################################################
const app = (() => {
let counterInterval;
let counter = 0;
function startCounter() {
counterInterval = setInterval(() => counter++, 1000);
}
function pauseCounter() {
clearInterval(counterInterval);
}
function showCounter() {
console.log(counter);
}
return {
startCounter,
pauseCounter,
showCounter,
}
})();
// ####################################################
// Run selected app method
// ####################################################
const argvs = process.argv.slice(2);
const [command, ...args] = argvs;
if (command === 'startCounter') {
app.startCounter();
}
if (command === 'pauseCounter') {
app.pauseCounter();
}
if (command === 'showCounter') {
app.showCounter();
}
如果我运行
node ./index.js startCounter
,应用程序将运行并且终端将锁定到进程中。我怎样才能做到这一点:
node ./index.js showCounter
的后续调用会显示最初运行的应用程序内的计数器值(而不是创建新进程)?在我看来,这个需求是一个很常见的用例,所以我认为 NodeJS 中一定有一种机制可以提供这种功能,但我找不到。我必须为此使用第三方工具包吗?
我的评论的解决方案。如前所述,您需要两个相互通信的进程。一个简单的方法是使用网络套接字。您没有说您正在使用什么操作系统。如果您使用 Windows,则需要调整网络创建/连接的内容。
index.js
const process = require("process");
process.env = Object.assign({
DEAMON: "false",
SOCKET: "/tmp/ipc-test.sock"
}, process.env);
console.log(`DAEMON: ${process.env.DEAMON}`)
if (process.env.DEAMON === "true") {
require("./server.js");
} else {
require("./client.js");
}
服务器.js
const net = require("net");
const fs = require("fs");
// cleanup previously used socket
try {
fs.unlinkSync(process.env.SOCKET);
} catch (err) {
if (err.code !== "ENOENT") {
console.error(err);
}
}
let counterInterval = null;
let counter = 0;
function startCounter() {
counterInterval = setInterval(() => {
counter++;
}, 1000);
}
function pauseCounter() {
clearInterval(counterInterval);
}
let server = net.createServer();
server.listen(process.env.SOCKET);
server.on("listening", () => {
console.log(`listening on ${process.env.SOCKET}`)
});
server.on("connection", (client) => {
console.log("Client connected");
client.on("data", (data) => {
let command = data.toString();
console.log("Client send command:", command)
if (command === 'startCounter') {
startCounter();
client.write("started");
} else if (command === 'pauseCounter') {
pauseCounter();
client.write("paused");
} else if (command === 'showCounter') {
client.write(`${counter}`);
} else {
client.write(`command "${command}" is invalid`);
}
});
});
客户端.js
const net = require("net");
let [command] = process.argv.slice(2);
let socket = net.connect(process.env.SOCKET);
socket.once("data", (response) => {
console.log(response.toString());
socket.destroy();
});
// send command over unix socket
socket.write(command);
程序的概念很简单:使用
DAEMON=true node index.js
启动服务器/后台服务,并尝试向服务器发送命令node index.js showCounter|startCounter|stopCounter|foo
当您运行服务器(
DEAMON=true nodemon index.js
)时,node.js 进程会创建一个网络套接字,并侦听可能连接的客户端。如果是这样,客户端发送命令,服务器执行该命令。 (开始计数器、停止计数器等...)
客户端部分也非常简单:它连接到网络套接字,并转发作为命令行参数传递的命令。当该命令未在服务器中实现时,它会响应“无效注释”。
非常简单直接。