版权声明:本文为迟思堂主人李迟原创文章,版权所有。可随便任意使用(包括学习研究商用),但由此带来的成果或后果,概与作者无关。胡乱修改的,不注明出处的,概不负责。 https://blog.csdn.net/subfate/article/details/87915135
本文是测试在运行时更新ecosystem配置文件的记录。
源码
服务端
/*
express简单示例
*/
//const log = require('../lib/log.js');
const http = require('http');
const express = require('express');
var cluster = require('cluster');
var os = require('os');
// const g_port = 4000;
const g_port = process.env["SERVER_PORT"];
const g_name = process.env["NODE_ENV"];
function test1()
{
app = express();
const server = http.createServer(app);
// 监听端口
server.listen(g_port, () => {
console.log(`111Express is listening on ${g_port}`);
});
// 访问首页,显示当时时间
app.get('/', function (req, res) {
console.log('111 got request from ...', req.url);
str = 'Hello World! now is: <br>';
myDate = new Date();
myDate.toLocaleString();
str += myDate;
res.send(str);
});
process.on('SIGINT', () => {
console.log('111 got sigint...\n');
const cleanUp = () => {
};
// 如果服务器关闭,延时2秒退出
server.close(() => {
// Stop after 10 secs
setTimeout(() => {
cleanUp();
process.exit();
}, 2000);
});
// Force close server after 15 secs
setTimeout((e) => {
console.log('Forcing server close !!!', e);
cleanUp();
process.exit(1);
}, 3000);
});
}
var g_cnt = 0;
// 这里创建worker是否必要?
// 解答:使用pm2的cluster模式,就不用手动写代码
function test2()
{
var numCPUs = 2; //os.cpus().length;
if (cluster.isMaster) {
// Master:
// Let's fork as many workers as you have CPU cores
for (var i = 0; i < numCPUs; ++i) {
cluster.fork();
}
} else {
// Worker:
// Let's spawn a HTTP server
// (Workers can share any TCP connection.
// In this case its a HTTP server)
console.log(`111 httpserver is listening on ${g_port}`);
http.createServer(function(req, res) {
res.writeHead(200);
console.log('got request from ...', req.url);
str = 'here is my voice: Hello World! now is: \n';
myDate = new Date();
myDate.toLocaleString();
str += myDate;
g_cnt++;
var cnt = ' cnt: ' + g_cnt.toString() + '\n';
str += cnt;
res.end(str);
}).listen(g_port);
}
}
// 该函数不使用worker方式
function test3()
{
console.log(`httpserver[${g_name}] is listening on ${g_port}`);
http.createServer(function(req, res) {
res.writeHead(200);
console.log('111 got request from ...', req.url);
str = '111 here is my voice: Hello World! now is: \n';
myDate = new Date();
myDate.toLocaleString();
str += myDate;
g_cnt++;
var cnt = ' cnt: ' + g_cnt.toString() + '\n';
str += cnt;
res.end(str);
}).listen(g_port);
}
// main函数
function main()
{
//test1();
//test2();
test3();
}
main();
客户端
/*
用于测试http服务器连接性,每0.5秒发送GET请求,如连接不上,返回错误,打印err
*/
var request = require('request');
const log = require('../lib/log.js');
const g_port = 4000;
function httpGet(url, requestData)
{
var head = {
url: url,
method: "GET",
json: true,
headers: {
"content-type": "application/json",
'User-Agent': 'git-oschina-hook',
'X-Gitee-Token': 'webhook password',
'X-Gitee-Event': 'Push Hook'
},
body: requestData
// body: JSON.stringify(requestData)
};
request(head, function fn(error, response, body) {
if (!error && response.statusCode == 200) {
log.print('=============GET content: \n', body) // 成功
}else{
log.print('err');
}
});
}
function getHttp()
{
var url = 'http://127.0.0.1:'+ g_port;
var msg = new Object();
msg['devid'] = '123456798';
msg['station'] = '01';
msg['stateCode']=='501';
//log.print('will get the http.');
httpGet(url, msg);
}
var g_loopId = null;
function startLoop()
{
g_loopId = setInterval(loopFunc, 500);
}
function stopLoop()
{
clearInterval(g_loopId);
}
function loopFunc()
{
getHttp();
}
function main()
{
log.print('start looping...');
startLoop();
}
main();
配置文件ecosystem.config.js
module.exports = {
// APP是一个数组,可以有多个
// 参数参考:https://pm2.io/doc/en/runtime/reference/ecosystem-file/
apps : [
{
name: 'app',
script: 'server.js',
args: 'null',
instances: 1,
//exec_mode: "cluster", // 集群模式,如不指定,默认为fork
autorestart: false,
min_uptime: "60s",
max_restarts: 3,
watch: false,
//error_file: "./logs/app-err.log",
//out_file: "./logs/app-out.log",
log: "./logs/app.log",
//log_date_format: "YYYY-MM-DD HH:mm Z", // pm2 log添加日期
max_memory_restart: '1G',
//listen_timeout: 3000,
kill_timeout: 3000,
// wait_ready: true,
env:
{
NODE_ENV: 'development',
SERVER_PORT: "4000",
},
env_production:
{
NODE_ENV: 'production1',
SERVER_PORT: "4000",
}
}
]
};
使用
启动服务端:
pm2 start
使用客户端连接,并观察输出日志:
node client.js
测试使用的命令:
重启pm2配置文件
pm2 reload ecosystem.config.js
重启实例
pm2 reload <ID>
测试项
下面分别进行不同的测试,大部分只写结论。
更新env中的字段值
可行。
如果修改的是env_production,则:
pm2 reload ecosystem.config.js --env production
另外在命令后面,加上不加上 --update-env ,好像没影响。
更新非env的字段
使用pm2 reload
,没效果,不成功。
新加实例
原来只有一个app,再加上一个app,但要修改名称和端口号,其它可相同。使用pm2 reload
,可以看到有新的实例运行。
减少实例
原来有2个app,减少一个。
使用pm2 reload
,没效果,不成功。
实例改名
原来app改名,端口没变化:
会启动新的实例,但提示端口被占用(因为没改)。
结论:只要名称不一样,pm2就认为是新的实例,要启动。打印信息会提示[PM2][WARN] Applications app1 not running, starting...
之类。所以,在mp2运行过程中,有一种方式“更新”实例,先将旧的实例停止(否则会提示占用端口号),将旧实例配置参数复制一份,将实例名称改为新的名称。再reload配置文件。更好的方法请参考下面示例。
删除实例再启动
pm2 del 1 (实例ID为1)
pm2 reload ecosystem.config.js
此时服务端的实例ID为2,1已经不存在了,但服务名称是一致的。
删除实例,修改实例,再启动
同上,可以修改pm2配置文件,也生效。
结论
1、pm2可以在原有基础上新加实例,直接reload ecosystem.config.js
即可启动新的实例。
2、通过pm2 del
和pm2 reload
可以修改某个实例的所有内容(注:只是理论,笔者主要关注log、端口等参数)。
3、如果要一切复原,终极办法是使用pm2 kill
。
李迟 2019.2.25 周一中午