用代码控制程序启停的几种实现方式
一、pm2方式
1.1原理
利用pm2模块启动node服务
1.2.优缺点
优点:有进程守护的功能,保证程序进程在死亡时可以自动重启。并且可以利用配置文件监听某重要文件修改时重启服务。
缺点:命令较多,不易操作
1.3 代码
const express = require("express");
const fs =require('fs');
const api = express();
let fsread = fs.readFileSync('./1.txt')
api.use('/get',function (req,res){
return res.send(JSON.parse(fsread))
})
api.use("/set",function (req,res){
let obj = {"B":Math.random()}
fs.writeFileSync('./1.txt',JSON.stringify(obj))
return res.send("修改成功")
})
api.listen(3000,function (){
console.log("启动成功")
})
我们在根目录下创建一个1.txt文件,并监听,当文件改变时就会重新启动项目
1.4 ecosystem.config.js 配置文件
module.exports = {
apps : [{
name : "app1", //启动的程序名称
script : "./pm2start.js", //要启动的文件
watch:"./1.txt", //要监听的文件
shutdown_with_message: true //使用process.send(' Shutdown ')而不是process来关闭应用程序。SIGINT杀死(pid)
}]
}
1.5 使用方法
安装模块
npm install pm2 -g
启动
pm2 start ecosystem.config.js
1.6 常用命令
pm2 start --name ”myapp01“ pm2方式启动并 并命名为 myapp01
pm2 stop 0 pm2 停止id为0的进程
pm2 stop all 停止所有的的进程
pm2 logs 查看日志
pm2 delete all 将pm2列表中进程全部删除
pm2 delete 0 将id为0的程序从pm2列表中删除进程
pm2 restart all 重启pm2所有进程
pm2 restart "myapp01" 重启名称为myapp01的进程
二、利用集群的方式
2.1原理
利用cluster模块,主进程用于控制工作进程启动和停止。
2.2优缺点
优点:当前有连接时,不会立刻死亡等没有连接时才会退出程序。
缺点:主进程死亡,子进程也会死亡。
2.3代码
创建Process01.js文件
const cluster = require("cluster");
//判断是不是主进程
if(cluster.isMaster){
//主进程控制程序的启动和停止
//衍生出一个新的进程
cluster.fork()
//监听进程断开连接
cluster.on('disconnect', (worker) => {
console.log(`The worker #${worker.id} has disconnected`);
});
/**用于控制子进程重启*/
const express = require('express');
const api =express();
api.listen(8001);
api.get('/restart',function (req,res){
//获取工作进程
const workers = Object.keys(cluster.workers);
const worker = cluster.workers[workers[0]];
console.log(`Stoping worker:${worker.process.pid}`);
//中断这个工作进程worker 会触发exit,并且切开 IPC 管道会通知
worker.on('exit',function (){
const new_worker = cluster.fork();
new_worker.on("listening",function(){
console.log("新的连接")
res.end("restart ok");
})
})
worker.disconnect(function (){
console.log("!!!!调用了回调函数")
});
})
}
else {
//普通进程
const express = require('express');
const api =express();
let a = Math.random();
api.use('/',function (req,res){
return res.send(a+"")
})
api.listen(9000);
}
创建Process02.js文件
const express =require('express');
const axios = require('axios')
const api = express();
var server;
api.use("/set",function (req,res){
//让当前程序退出
server.close()
return res.send("777777777")
})
server = api.listen(3001,function (){
console.log('3001启动成功')
})
//此处可以监听进程退出事件
process.on('exit',function (){
console.log("SSSSS")
})
主进程(Process01)用于负责工作进程的创建和销毁,工作进程时真正的工作进程(可以创建多个)。当调用主进程的reset接
口时,杀死当前进程,创建一个新的进程。不过此方法的响应时间过程,本人测试有一分钟到二分钟左右,可能不
同环境相应的时间不一样。它是当所有连接中断时,才会销毁创建新的工作进程。这是因为disconnect’ 和 ‘exit’
事件之间可能存在延迟。
三、利用父子进程的方式
3.1原理
利用child_process模块创建子进程,由父进程控制子进程的创建和销毁来达到项目重启。
3.2优缺点
优点:响应快,不会等其他代码执行完毕。
缺点:主进程死亡,子进程也会死亡
3.3.代码
创建master.js文件
/****
* 利用主进程创建子进程,
* 主进程控制子进程的销毁和创建即可!
* ***/
const child_process = require('child_process')
//启动则创建子进程
let child = child_process.fork('./proces');
const express =require("express");
const app = express();
app.use("/reset",function (req,res){
//调用时通知子进程退出,
child.send(JSON.stringify({cmd:"exit"}))
//创建新的子进程
child = child_process.fork('./proces');
return res.send("重启项目")
})
app.listen(8000,function (){
console.log("监听成功")
})
创建index.js文件
const express =require('express')
const app = express();
let a = Math.random();
app.use('/get',function (req,res){
return res.send(a+'我是')
})
app.use('/set',function (req,res){
})
process.on('exit',function (){
console.log("监听到了退出任务")
})
process.on('message',function (msg){
console.log("监听到了退出任务1111",msg)
process.exit()
})
app.listen(3001,function (){
console.log("~~~监听成功")
})
启动master文件时,会自动创建一个进程,当我们调用主进程的reset重启接口时,首先销毁进程,在创建即可。
四、进程间通讯
4.1原理
利用node-ipc进程通讯模块,告诉程序自动退出,同时调用着再用cmd命令启动项目即可
4.2优缺点
优点:响应快,不会等其他代码执行完毕
缺点:调用程序一旦死亡,主进程也一并死亡
4.3代码
客户端client.js文件
const ipc = require("node-ipc").default;
const socketPath = '/tmp/ipc.sock';
const { exec } = require('child_process');
ipc.connectTo('world', socketPath,function (socket){
ipc.of.world.on(
'connect',
function() {
//负责发送命令给服务端
ipc.of.world.emit(
'currentDate',
{
message: new Date().toISOString()
}
);
ipc.disconnect('world');
}
);
})
//调用脚本重新启动
exec('x.bat', { encoding: 'buffer' }, (error, stdout) => {
console.log('stdout1',error);
});
服务端server.js文件
const ipc = require("node-ipc").default;
const api = require('express')();
let AA = Math.random()
api.use("/get",function (req,res){
return res.send("aaaa"+AA)
})
api.listen("3002",function (){
console.log("监听成功")
})
const socketPath = '/tmp/ipc.sock';
//创建服务器
ipc.serve(socketPath)
//监听
ipc.server.on("currentDate",function (data,socket) {
console.log(`pid ${process.pid} got: `, data);
process.exit()
})
//启动
ipc.server.start();
process.on('exit',function (){
console.log("程序退出")
})
x.bat 文件
node server.js
先启动server文件,在启动cilent即可完成重启操作