feat: 초기 프로젝트 설정 및 룰.md 파일 추가

This commit is contained in:
2025-07-28 09:53:31 +09:00
commit 09a4d38512
8165 changed files with 1021855 additions and 0 deletions

View File

@@ -0,0 +1,909 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
'use strict';
/**
* @file ActionMethod like restart, stop, monitor... are here
* @author Alexandre Strzelewicz <as@unitech.io>
* @project PM2
*/
var fs = require('fs');
var path = require('path');
var eachLimit = require('async/eachLimit');
var os = require('os');
var p = path;
var cst = require('../../constants.js');
var pkg = require('../../package.json');
var pidusage = require('pidusage');
var util = require('util');
var debug = require('debug')('pm2:ActionMethod');
var Utility = require('../Utility');
/**
* Description
* @method exports
* @param {} God
* @return
*/
module.exports = function(God) {
/**
* Description
* @method getMonitorData
* @param {} env
* @param {} cb
* @return
*/
God.getMonitorData = function getMonitorData(env, cb) {
var processes = God.getFormatedProcesses();
var pids = processes.filter(filterBadProcess)
.map(function(pro, i) {
var pid = getProcessId(pro)
return pid;
})
// No pids, return empty statistics
if (pids.length === 0) {
return cb(null, processes.map(function(pro) {
pro['monit'] = {
memory : 0,
cpu : 0
};
return pro
}))
}
pidusage(pids, function retPidUsage(err, statistics) {
// Just log, we'll set empty statistics
if (err) {
console.error('Error caught while calling pidusage');
console.error(err);
return cb(null, processes.map(function(pro) {
pro['monit'] = {
memory : 0,
cpu : 0
};
return pro
}))
}
if (!statistics) {
console.error('Statistics is not defined!')
return cb(null, processes.map(function(pro) {
pro['monit'] = {
memory : 0,
cpu : 0
};
return pro
}))
}
processes = processes.map(function(pro) {
if (filterBadProcess(pro) === false) {
pro['monit'] = {
memory : 0,
cpu : 0
};
return pro;
}
var pid = getProcessId(pro);
var stat = statistics[pid];
if (!stat) {
pro['monit'] = {
memory : 0,
cpu : 0
};
return pro;
}
pro['monit'] = {
memory: stat.memory,
cpu: Math.round(stat.cpu * 10) / 10
};
return pro;
});
cb(null, processes);
});
};
/**
* Description
* @method dumpProcessList
* @param {} cb
* @return
*/
God.dumpProcessList = function(cb) {
var process_list = [];
var apps = Utility.clone(God.getFormatedProcesses());
var that = this;
// Don't override the actual dump file if process list is empty
// unless user explicitely did `pm2 dump`.
// This often happens when PM2 crashed, we don't want to override
// the dump file with an empty list of process.
if (!apps[0]) {
debug('[PM2] Did not override dump file because list of processes is empty');
return cb(null, {success:true, process_list: process_list});
}
function fin(err) {
// try to fix issues with empty dump file
// like #3485
if (process_list.length === 0) {
// fix : if no dump file, no process, only module and after pm2 update
if (!fs.existsSync(cst.DUMP_FILE_PATH) && typeof that.clearDump === 'function') {
that.clearDump(function(){});
}
// if no process in list don't modify dump file
// process list should not be empty
return cb(null, {success:true, process_list: process_list});
}
// Back up dump file
try {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH));
}
} catch (e) {
console.error(e.stack || e);
}
// Overwrite dump file, delete if broken
try {
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(process_list));
} catch (e) {
console.error(e.stack || e);
try {
// try to backup file
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fs.writeFileSync(cst.DUMP_FILE_PATH, fs.readFileSync(cst.DUMP_BACKUP_FILE_PATH));
}
} catch (e) {
// don't keep broken file
fs.unlinkSync(cst.DUMP_FILE_PATH);
console.error(e.stack || e);
}
}
return cb(null, {success:true, process_list: process_list});
}
function saveProc(apps) {
if (!apps[0])
return fin(null);
delete apps[0].pm2_env.instances;
delete apps[0].pm2_env.pm_id;
// Do not dump modules
if (!apps[0].pm2_env.pmx_module)
process_list.push(apps[0].pm2_env);
apps.shift();
return saveProc(apps);
}
saveProc(apps);
};
/**
* Description
* @method ping
* @param {} env
* @param {} cb
* @return CallExpression
*/
God.ping = function(env, cb) {
return cb(null, {msg : 'pong'});
};
/**
* Description
* @method notifyKillPM2
*/
God.notifyKillPM2 = function() {
God.pm2_being_killed = true;
};
/**
* Duplicate a process
* @method duplicateProcessId
* @param {} id
* @param {} cb
* @return CallExpression
*/
God.duplicateProcessId = function(id, cb) {
if (!(id in God.clusters_db))
return cb(God.logAndGenerateError(id + ' id unknown'), {});
if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env)
return cb(God.logAndGenerateError('Error when getting proc || proc.pm2_env'), {});
var proc = Utility.clone(God.clusters_db[id].pm2_env);
delete proc.created_at;
delete proc.pm_id;
delete proc.unique_id;
// generate a new unique id for new process
proc.unique_id = Utility.generateUUID()
God.injectVariables(proc, function inject (_err, proc) {
return God.executeApp(Utility.clone(proc), function (err, clu) {
if (err) return cb(err);
God.notify('start', clu, true);
return cb(err, Utility.clone(clu));
});
});
};
/**
* Start a stopped process by ID
* @method startProcessId
* @param {} id
* @param {} cb
* @return CallExpression
*/
God.startProcessId = function(id, cb) {
if (!(id in God.clusters_db))
return cb(God.logAndGenerateError(id + ' id unknown'), {});
var proc = God.clusters_db[id];
if (proc.pm2_env.status == cst.ONLINE_STATUS)
return cb(God.logAndGenerateError('process already online'), {});
if (proc.pm2_env.status == cst.LAUNCHING_STATUS)
return cb(God.logAndGenerateError('process already started'), {});
if (proc.process && proc.process.pid)
return cb(God.logAndGenerateError('Process with pid ' + proc.process.pid + ' already exists'), {});
return God.executeApp(God.clusters_db[id].pm2_env, function(err, proc) {
return cb(err, Utility.clone(proc));
});
};
/**
* Stop a process and set it on state 'stopped'
* @method stopProcessId
* @param {} id
* @param {} cb
* @return Literal
*/
God.stopProcessId = function(id, cb) {
if (typeof id == 'object' && 'id' in id)
id = id.id;
if (!(id in God.clusters_db))
return cb(God.logAndGenerateError(id + ' : id unknown'), {});
var proc = God.clusters_db[id];
//clear time-out restart task
clearTimeout(proc.pm2_env.restart_task);
if (proc.pm2_env.status == cst.STOPPED_STATUS) {
proc.process.pid = 0;
return cb(null, God.getFormatedProcess(id));
}
// state == 'none' means that the process is not online yet
if (proc.state && proc.state === 'none')
return setTimeout(function() { God.stopProcessId(id, cb); }, 250);
console.log('Stopping app:%s id:%s', proc.pm2_env.name, proc.pm2_env.pm_id);
proc.pm2_env.status = cst.STOPPING_STATUS;
if (!proc.process.pid) {
console.error('app=%s id=%d does not have a pid', proc.pm2_env.name, proc.pm2_env.pm_id);
proc.pm2_env.status = cst.STOPPED_STATUS;
return cb(null, { error : true, message : 'could not kill process w/o pid'});
}
God.killProcess(proc.process.pid, proc.pm2_env, function(err) {
proc.pm2_env.status = cst.STOPPED_STATUS;
God.notify('exit', proc);
if (err && err.type && err.type === 'timeout') {
console.error('app=%s id=%d pid=%s could not be stopped',
proc.pm2_env.name,
proc.pm2_env.pm_id,
proc.process.pid);
proc.pm2_env.status = cst.ERRORED_STATUS;
return cb(null, God.getFormatedProcess(id));
}
if (proc.pm2_env.pm_id.toString().indexOf('_old_') !== 0) {
try {
fs.unlinkSync(proc.pm2_env.pm_pid_path);
} catch (e) {}
}
if (proc.pm2_env.axm_actions) proc.pm2_env.axm_actions = [];
if (proc.pm2_env.axm_monitor) proc.pm2_env.axm_monitor = {};
proc.process.pid = 0;
return cb(null, God.getFormatedProcess(id));
});
};
God.resetMetaProcessId = function(id, cb) {
if (!(id in God.clusters_db))
return cb(God.logAndGenerateError(id + ' id unknown'), {});
if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env)
return cb(God.logAndGenerateError('Error when getting proc || proc.pm2_env'), {});
God.clusters_db[id].pm2_env.created_at = Utility.getDate();
God.clusters_db[id].pm2_env.unstable_restarts = 0;
God.clusters_db[id].pm2_env.restart_time = 0;
return cb(null, God.getFormatedProcesses());
};
/**
* Delete a process by id
* It will stop it and remove it from the database
* @method deleteProcessId
* @param {} id
* @param {} cb
* @return Literal
*/
God.deleteProcessId = function(id, cb) {
God.deleteCron(id);
God.stopProcessId(id, function(err, proc) {
if (err) return cb(God.logAndGenerateError(err), {});
// ! transform to slow object
delete God.clusters_db[id];
if (Object.keys(God.clusters_db).length == 0)
God.next_id = 0;
return cb(null, proc);
});
return false;
};
/**
* Restart a process ID
* If the process is online it will not put it on state stopped
* but directly kill it and let God restart it
* @method restartProcessId
* @param {} id
* @param {} cb
* @return Literal
*/
God.restartProcessId = function(opts, cb) {
var id = opts.id;
var env = opts.env || {};
if (typeof(id) === 'undefined')
return cb(God.logAndGenerateError('opts.id not passed to restartProcessId', opts));
if (!(id in God.clusters_db))
return cb(God.logAndGenerateError('God db process id unknown'), {});
var proc = God.clusters_db[id];
God.resetState(proc.pm2_env);
God.deleteCron(id);
/**
* Merge new application configuration on restart
* Same system in reloadProcessId and softReloadProcessId
*/
Utility.extend(proc.pm2_env.env, env);
Utility.extendExtraConfig(proc, opts);
if (God.pm2_being_killed) {
return cb(God.logAndGenerateError('[RestartProcessId] PM2 is being killed, stopping restart procedure...'));
}
if (proc.pm2_env.status === cst.ONLINE_STATUS || proc.pm2_env.status === cst.LAUNCHING_STATUS) {
God.stopProcessId(id, function(err) {
if (God.pm2_being_killed)
return cb(God.logAndGenerateError('[RestartProcessId] PM2 is being killed, stopping restart procedure...'));
proc.pm2_env.restart_time += 1;
return God.startProcessId(id, cb);
});
return false;
}
else {
debug('[restart] process not online, starting it');
return God.startProcessId(id, cb);
}
};
/**
* Restart all process by name
* @method restartProcessName
* @param {} name
* @param {} cb
* @return Literal
*/
God.restartProcessName = function(name, cb) {
var processes = God.findByName(name);
if (processes && processes.length === 0)
return cb(God.logAndGenerateError('Unknown process'), {});
eachLimit(processes, cst.CONCURRENT_ACTIONS, function(proc, next) {
if (God.pm2_being_killed)
return next('[Watch] PM2 is being killed, stopping restart procedure...');
if (proc.pm2_env.status === cst.ONLINE_STATUS)
return God.restartProcessId({id:proc.pm2_env.pm_id}, next);
else if (proc.pm2_env.status !== cst.STOPPING_STATUS
&& proc.pm2_env.status !== cst.LAUNCHING_STATUS)
return God.startProcessId(proc.pm2_env.pm_id, next);
else
return next(util.format('[Watch] Process name %s is being stopped so I won\'t restart it', name));
}, function(err) {
if (err) return cb(God.logAndGenerateError(err));
return cb(null, God.getFormatedProcesses());
});
return false;
};
/**
* Send system signal to process id
* @method sendSignalToProcessId
* @param {} opts
* @param {} cb
* @return CallExpression
*/
God.sendSignalToProcessId = function(opts, cb) {
var id = opts.process_id;
var signal = opts.signal;
if (!(id in God.clusters_db))
return cb(God.logAndGenerateError(id + ' id unknown'), {});
var proc = God.clusters_db[id];
//God.notify('send signal ' + signal, proc, true);
try {
process.kill(God.clusters_db[id].process.pid, signal);
} catch(e) {
return cb(God.logAndGenerateError('Error when sending signal (signal unknown)'), {});
}
return cb(null, God.getFormatedProcesses());
};
/**
* Send system signal to all processes by name
* @method sendSignalToProcessName
* @param {} opts
* @param {} cb
* @return
*/
God.sendSignalToProcessName = function(opts, cb) {
var processes = God.findByName(opts.process_name);
var signal = opts.signal;
if (processes && processes.length === 0)
return cb(God.logAndGenerateError('Unknown process name'), {});
eachLimit(processes, cst.CONCURRENT_ACTIONS, function(proc, next) {
if (proc.pm2_env.status == cst.ONLINE_STATUS || proc.pm2_env.status == cst.LAUNCHING_STATUS) {
try {
process.kill(proc.process.pid, signal);
} catch(e) {
return next(e);
}
}
return setTimeout(next, 200);
}, function(err) {
if (err) return cb(God.logAndGenerateError(err), {});
return cb(null, God.getFormatedProcesses());
});
};
/**
* Stop watching daemon
* @method stopWatch
* @param {} method
* @param {} value
* @param {} fn
* @return
*/
God.stopWatch = function(method, value, fn) {
var env = null;
if (method == 'stopAll' || method == 'deleteAll') {
var processes = God.getFormatedProcesses();
processes.forEach(function(proc) {
God.clusters_db[proc.pm_id].pm2_env.watch = false;
God.watch.disable(proc.pm2_env);
});
} else {
if (method.indexOf('ProcessId') !== -1) {
env = God.clusters_db[value];
} else if (method.indexOf('ProcessName') !== -1) {
env = God.clusters_db[God.findByName(value)];
}
if (env) {
God.watch.disable(env.pm2_env);
env.pm2_env.watch = false;
}
}
return fn(null, {success:true});
};
/**
* Toggle watching daemon
* @method toggleWatch
* @param {String} method
* @param {Object} application environment, should include id
* @param {Function} callback
*/
God.toggleWatch = function(method, value, fn) {
var env = null;
if (method == 'restartProcessId') {
env = God.clusters_db[value.id];
} else if(method == 'restartProcessName') {
env = God.clusters_db[God.findByName(value)];
}
if (env) {
env.pm2_env.watch = !env.pm2_env.watch;
if (env.pm2_env.watch)
God.watch.enable(env.pm2_env);
else
God.watch.disable(env.pm2_env);
}
return fn(null, {success:true});
};
/**
* Start Watch
* @method startWatch
* @param {String} method
* @param {Object} application environment, should include id
* @param {Function} callback
*/
God.startWatch = function(method, value, fn) {
var env = null;
if (method == 'restartProcessId') {
env = God.clusters_db[value.id];
} else if(method == 'restartProcessName') {
env = God.clusters_db[God.findByName(value)];
}
if (env) {
if (env.pm2_env.watch)
return fn(null, {success:true, notrestarted:true});
God.watch.enable(env.pm2_env);
//env.pm2_env.env.watch = true;
env.pm2_env.watch = true;
}
return fn(null, {success:true});
};
/**
* Description
* @method reloadLogs
* @param {} opts
* @param {} cb
* @return CallExpression
*/
God.reloadLogs = function(opts, cb) {
console.log('Reloading logs...');
var processIds = Object.keys(God.clusters_db);
processIds.forEach(function (id) {
var cluster = God.clusters_db[id];
console.log('Reloading logs for process id %d', id);
if (cluster && cluster.pm2_env) {
// Cluster mode
if (cluster.send && cluster.pm2_env.exec_mode == 'cluster_mode') {
try {
cluster.send({
type:'log:reload'
});
} catch(e) {
console.error(e.message || e);
}
}
// Fork mode
else if (cluster._reloadLogs) {
cluster._reloadLogs(function(err) {
if (err) God.logAndGenerateError(err);
});
}
}
});
return cb(null, {});
};
/**
* Send Line To Stdin
* @method sendLineToStdin
* @param Object packet
* @param String pm_id Process ID
* @param String line Line to send to process stdin
*/
God.sendLineToStdin = function(packet, cb) {
if (typeof(packet.pm_id) == 'undefined' || !packet.line)
return cb(God.logAndGenerateError('pm_id or line field missing'), {});
var pm_id = packet.pm_id;
var line = packet.line;
var proc = God.clusters_db[pm_id];
if (!proc)
return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> unknown.'), {});
if (proc.pm2_env.exec_mode == 'cluster_mode')
return cb(God.logAndGenerateError('Cannot send line to processes in cluster mode'), {});
if (proc.pm2_env.status != cst.ONLINE_STATUS && proc.pm2_env.status != cst.LAUNCHING_STATUS)
return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> offline.'), {});
try {
proc.stdin.write(line, function() {
return cb(null, {
pm_id : pm_id,
line : line
});
});
} catch(e) {
return cb(God.logAndGenerateError(e), {});
}
}
/**
* @param {object} packet
* @param {function} cb
*/
God.sendDataToProcessId = function(packet, cb) {
if (typeof(packet.id) == 'undefined' ||
typeof(packet.data) == 'undefined' ||
!packet.topic)
return cb(God.logAndGenerateError('ID, DATA or TOPIC field is missing'), {});
var pm_id = packet.id;
var data = packet.data;
var proc = God.clusters_db[pm_id];
if (!proc)
return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> unknown.'), {});
if (proc.pm2_env.status != cst.ONLINE_STATUS && proc.pm2_env.status != cst.LAUNCHING_STATUS)
return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> offline.'), {});
try {
proc.send(packet);
}
catch(e) {
return cb(God.logAndGenerateError(e), {});
}
return cb(null, {
success: true,
data : packet
});
};
/**
* Send Message to Process by id or name
* @method msgProcess
* @param {} cmd
* @param {} cb
* @return Literal
*/
God.msgProcess = function(cmd, cb) {
if ('id' in cmd) {
var id = cmd.id;
if (!(id in God.clusters_db))
return cb(God.logAndGenerateError(id + ' id unknown'), {});
var proc = God.clusters_db[id];
var action_exist = false;
proc.pm2_env.axm_actions.forEach(function(action) {
if (action.action_name == cmd.msg) {
action_exist = true;
// Reset output buffer
action.output = [];
}
});
if (action_exist == false) {
return cb(God.logAndGenerateError('Action doesn\'t exist ' + cmd.msg + ' for ' + proc.pm2_env.name), {});
}
if (proc.pm2_env.status == cst.ONLINE_STATUS || proc.pm2_env.status == cst.LAUNCHING_STATUS) {
/*
* Send message
*/
if (cmd.opts == null && !cmd.uuid)
proc.send(cmd.msg);
else
proc.send(cmd);
return cb(null, { process_count : 1, success : true });
}
else
return cb(God.logAndGenerateError(id + ' : id offline'), {});
}
else if ('name' in cmd) {
/*
* As names are not unique in case of cluster, this
* will send msg to all process matching 'name'
*/
var name = cmd.name;
var arr = Object.keys(God.clusters_db);
var sent = 0;
(function ex(arr) {
if (arr[0] == null || !arr) {
return cb(null, {
process_count : sent,
success : true
});
}
var id = arr[0];
if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env) {
arr.shift();
return ex(arr);
}
var proc_env = God.clusters_db[id].pm2_env;
const isActionAvailable = proc_env.axm_actions.find(action => action.action_name === cmd.msg) !== undefined
// if action doesn't exist for this app
// try with the next one
if (isActionAvailable === false) {
arr.shift();
return ex(arr);
}
if ((p.basename(proc_env.pm_exec_path) == name ||
proc_env.name == name ||
proc_env.namespace == name ||
name == 'all') &&
(proc_env.status == cst.ONLINE_STATUS ||
proc_env.status == cst.LAUNCHING_STATUS)) {
proc_env.axm_actions.forEach(function(action) {
if (action.action_name == cmd.msg) {
action_exist = true;
}
});
if (action_exist == false || proc_env.axm_actions.length == 0) {
arr.shift();
return ex(arr);
}
if (cmd.opts == null)
God.clusters_db[id].send(cmd.msg);
else
God.clusters_db[id].send(cmd);
sent++;
arr.shift();
return ex(arr);
}
else {
arr.shift();
return ex(arr);
}
return false;
})(arr);
}
else return cb(God.logAndGenerateError('method requires name or id field'), {});
return false;
};
/**
* Description
* @method getVersion
* @param {} env
* @param {} cb
* @return CallExpression
*/
God.getVersion = function(env, cb) {
process.nextTick(function() {
return cb(null, pkg.version);
});
};
God.monitor = function Monitor(pm_id, cb) {
if (!God.clusters_db[pm_id] || !God.clusters_db[pm_id].pm2_env)
return cb(new Error('Unknown pm_id'));
God.clusters_db[pm_id].pm2_env._km_monitored = true;
return cb(null, { success : true, pm_id : pm_id });
}
God.unmonitor = function Monitor(pm_id, cb) {
if (!God.clusters_db[pm_id] || !God.clusters_db[pm_id].pm2_env)
return cb(new Error('Unknown pm_id'));
God.clusters_db[pm_id].pm2_env._km_monitored = false;
return cb(null, { success : true, pm_id : pm_id });
}
God.getReport = function(arg, cb) {
var report = {
pm2_version : pkg.version,
node_version : 'N/A',
node_path : process.env['_'] || 'not found',
argv0 : process.argv0,
argv : process.argv,
user : process.env.USER,
uid : (cst.IS_WINDOWS === false && process.geteuid) ? process.geteuid() : 'N/A',
gid : (cst.IS_WINDOWS === false && process.getegid) ? process.getegid() : 'N/A',
env : process.env,
managed_apps : Object.keys(God.clusters_db).length,
started_at : God.started_at
};
if (process.versions && process.versions.node) {
report.node_version = process.versions.node;
}
process.nextTick(function() {
return cb(null, report);
});
};
};
function filterBadProcess(pro) {
if (pro.pm2_env.status !== cst.ONLINE_STATUS) {
return false;
}
if (pro.pm2_env.axm_options && pro.pm2_env.axm_options.pid) {
if (isNaN(pro.pm2_env.axm_options.pid)) {
return false;
}
}
return true;
}
function getProcessId(pro) {
var pid = pro.pid
if (pro.pm2_env.axm_options && pro.pm2_env.axm_options.pid) {
pid = pro.pm2_env.axm_options.pid;
}
return pid
}

97
api.hyungi.net/node_modules/pm2/lib/God/ClusterMode.js generated vendored Normal file
View File

@@ -0,0 +1,97 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
'use strict';
/**
* @file Cluster execution functions related
* @author Alexandre Strzelewicz <as@unitech.io>
* @project PM2
*/
var cluster = require('cluster');
var Utility = require('../Utility.js');
var pkg = require('../../package.json');
/**
* Description
* @method exports
* @param {} God
* @return
*/
module.exports = function ClusterMode(God) {
/**
* For Node apps - Cluster mode
* It will wrap the code and enable load-balancing mode
* @method nodeApp
* @param {} env_copy
* @param {} cb
* @return Literal
*/
God.nodeApp = function nodeApp(env_copy, cb){
var clu = null;
console.log(`App [${env_copy.name}:${env_copy.pm_id}] starting in -cluster mode-`)
if (env_copy.node_args && Array.isArray(env_copy.node_args)) {
cluster.settings.execArgv = env_copy.node_args;
}
env_copy._pm2_version = pkg.version;
try {
// node.js cluster clients can not receive deep-level objects or arrays in the forked process, e.g.:
// { "args": ["foo", "bar"], "env": { "foo1": "bar1" }} will be parsed to
// { "args": "foo, bar", "env": "[object Object]"}
// So we passing a stringified JSON here.
clu = cluster.fork({pm2_env: JSON.stringify(env_copy), windowsHide: true});
} catch(e) {
God.logAndGenerateError(e);
return cb(e);
}
clu.pm2_env = env_copy;
/**
* Broadcast message to God
*/
clu.on('message', function cluMessage(msg) {
/*********************************
* If you edit this function
* Do the same in ForkMode.js !
*********************************/
if (msg.data && msg.type) {
return God.bus.emit(msg.type ? msg.type : 'process:msg', {
at : Utility.getDate(),
data : msg.data,
process : {
pm_id : clu.pm2_env.pm_id,
name : clu.pm2_env.name,
rev : (clu.pm2_env.versioning && clu.pm2_env.versioning.revision) ? clu.pm2_env.versioning.revision : null,
namespace : clu.pm2_env.namespace
}
});
}
else {
if (typeof msg == 'object' && 'node_version' in msg) {
clu.pm2_env.node_version = msg.node_version;
return false;
}
return God.bus.emit('process:msg', {
at : Utility.getDate(),
raw : msg,
process : {
pm_id : clu.pm2_env.pm_id,
name : clu.pm2_env.name,
namespace : clu.pm2_env.namespace
}
});
}
});
return cb(null, clu);
};
};

293
api.hyungi.net/node_modules/pm2/lib/God/ForkMode.js generated vendored Normal file
View File

@@ -0,0 +1,293 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
'use strict';
/**
* @file Fork execution related functions
* @author Alexandre Strzelewicz <as@unitech.io>
* @project PM2
*/
var log = require('debug')('pm2:fork_mode');
var fs = require('fs');
var Utility = require('../Utility.js');
var path = require('path');
var dayjs = require('dayjs');
var semver = require('semver')
/**
* Description
* @method exports
* @param {} God
* @return
*/
module.exports = function ForkMode(God) {
/**
* For all apps - FORK MODE
* fork the app
* @method forkMode
* @param {} pm2_env
* @param {} cb
* @return
*/
God.forkMode = function forkMode(pm2_env, cb) {
var command = '';
var args = [];
console.log(`App [${pm2_env.name}:${pm2_env.pm_id}] starting in -fork mode-`)
var spawn = require('child_process').spawn;
var interpreter = pm2_env.exec_interpreter || 'node';
var pidFile = pm2_env.pm_pid_path;
if (interpreter !== 'none') {
command = interpreter;
if (pm2_env.node_args && Array.isArray(pm2_env.node_args)) {
args = args.concat(pm2_env.node_args);
}
// Deprecated - to remove at some point
if (process.env.PM2_NODE_OPTIONS) {
args = args.concat(process.env.PM2_NODE_OPTIONS.split(' '));
}
if (interpreter === 'node' || RegExp('node$').test(interpreter)) {
args.push(path.resolve(path.dirname(module.filename), '..', 'ProcessContainerFork.js'));
}
else
args.push(pm2_env.pm_exec_path);
}
else {
command = pm2_env.pm_exec_path;
args = [ ];
}
if (pm2_env.args) {
args = args.concat(pm2_env.args);
}
// piping stream o file
var stds = {
out: pm2_env.pm_out_log_path,
err: pm2_env.pm_err_log_path
};
// entire log std if necessary.
if ('pm_log_path' in pm2_env){
stds.std = pm2_env.pm_log_path;
}
log("stds: %j", stds);
Utility.startLogging(stds, function(err, result) {
if (err) {
God.logAndGenerateError(err);
return cb(err);
};
try {
var options = {
env : pm2_env,
detached : true,
cwd : pm2_env.pm_cwd || process.cwd(),
stdio : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core
}
if (typeof(pm2_env.windowsHide) === "boolean") {
options.windowsHide = pm2_env.windowsHide;
} else {
options.windowsHide = true;
}
if (pm2_env.uid) {
options.uid = pm2_env.uid
}
if (pm2_env.gid) {
options.gid = pm2_env.gid
}
var cspr = spawn(command, args, options);
} catch(e) {
God.logAndGenerateError(e);
return cb(e);
}
if (!cspr || !cspr.stderr || !cspr.stdout) {
var fatalError = new Error('Process could not be forked properly, check your system health')
God.logAndGenerateError(fatalError);
return cb(fatalError);
}
cspr.process = {};
cspr.process.pid = cspr.pid;
cspr.pm2_env = pm2_env;
function transformLogToJson(pm2_env, type, data) {
return JSON.stringify({
message : data.toString(),
timestamp : pm2_env.log_date_format ? dayjs().format(pm2_env.log_date_format) : new Date().toISOString(),
type : type,
process_id : cspr.pm2_env.pm_id,
app_name : cspr.pm2_env.name
}) + '\n'
}
function prefixLogWithDate(pm2_env, data) {
var log_data = []
log_data = data.toString().split('\n')
if (log_data.length > 1)
log_data.pop()
log_data = log_data.map(line => `${dayjs().format(pm2_env.log_date_format)}: ${line}\n`)
log_data = log_data.join('')
return log_data
}
cspr.stderr.on('data', function forkErrData(data) {
var log_data = null;
// via --out /dev/null --err /dev/null
if (pm2_env.disable_logs === true) return false;
if (pm2_env.log_type && pm2_env.log_type === 'json')
log_data = transformLogToJson(pm2_env, 'err', data)
else if (pm2_env.log_date_format)
log_data = prefixLogWithDate(pm2_env, data)
else
log_data = data.toString();
God.bus.emit('log:err', {
process : {
pm_id : cspr.pm2_env.pm_id,
name : cspr.pm2_env.name,
rev : (cspr.pm2_env.versioning && cspr.pm2_env.versioning.revision) ? cspr.pm2_env.versioning.revision : null,
namespace : cspr.pm2_env.namespace
},
at : Utility.getDate(),
data : log_data
});
if (Utility.checkPathIsNull(pm2_env.pm_err_log_path) &&
(!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path))) {
return false;
}
stds.std && stds.std.write && stds.std.write(log_data);
stds.err && stds.err.write && stds.err.write(log_data);
});
cspr.stdout.on('data', function forkOutData(data) {
var log_data = null;
if (pm2_env.disable_logs === true)
return false;
if (pm2_env.log_type && pm2_env.log_type === 'json')
log_data = transformLogToJson(pm2_env, 'out', data)
else if (pm2_env.log_date_format)
log_data = prefixLogWithDate(pm2_env, data)
else
log_data = data.toString()
God.bus.emit('log:out', {
process : {
pm_id : cspr.pm2_env.pm_id,
name : cspr.pm2_env.name,
rev : (cspr.pm2_env.versioning && cspr.pm2_env.versioning.revision) ? cspr.pm2_env.versioning.revision : null,
namespace : cspr.pm2_env.namespace
},
at : Utility.getDate(),
data : log_data
});
if (Utility.checkPathIsNull(pm2_env.pm_out_log_path) &&
(!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
return false;
stds.std && stds.std.write && stds.std.write(log_data);
stds.out && stds.out.write && stds.out.write(log_data);
});
/**
* Broadcast message to God
*/
cspr.on('message', function forkMessage(msg) {
/*********************************
* If you edit this function
* Do the same in ClusterMode.js !
*********************************/
if (msg.data && msg.type) {
process.nextTick(function() {
return God.bus.emit(msg.type ? msg.type : 'process:msg', {
at : Utility.getDate(),
data : msg.data,
process : {
pm_id : cspr.pm2_env.pm_id,
name : cspr.pm2_env.name,
versioning : cspr.pm2_env.versioning,
namespace : cspr.pm2_env.namespace
}
});
});
}
else {
if (typeof msg == 'object' && 'node_version' in msg) {
cspr.pm2_env.node_version = msg.node_version;
return false;
}
return God.bus.emit('process:msg', {
at : Utility.getDate(),
raw : msg,
process : {
pm_id : cspr.pm2_env.pm_id,
name : cspr.pm2_env.name,
namespace : cspr.pm2_env.namespace
}
});
}
});
try {
var pid = cspr.pid
if (typeof(pid) !== 'undefined')
fs.writeFileSync(pidFile, pid.toString());
} catch (e) {
console.error(e.stack || e);
}
cspr.once('exit', function forkClose(status) {
try {
for(var k in stds){
if (stds[k] && stds[k].destroy) stds[k].destroy();
else if (stds[k] && stds[k].end) stds[k].end();
else if (stds[k] && stds[k].close) stds[k].close();
stds[k] = stds[k]._file;
}
} catch(e) { God.logAndGenerateError(e);}
});
cspr._reloadLogs = function(cb) {
try {
for (var k in stds){
if (stds[k] && stds[k].destroy) stds[k].destroy();
else if (stds[k] && stds[k].end) stds[k].end();
else if (stds[k] && stds[k].close) stds[k].close();
stds[k] = stds[k]._file;
}
} catch(e) { God.logAndGenerateError(e);}
//cspr.removeAllListeners();
Utility.startLogging(stds, cb);
};
cspr.unref();
return cb(null, cspr);
});
};
};

265
api.hyungi.net/node_modules/pm2/lib/God/Methods.js generated vendored Normal file
View File

@@ -0,0 +1,265 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
'use strict';
/**
* @file Utilities for PM2
* @author Alexandre Strzelewicz <as@unitech.io>
* @project PM2
*/
var p = require('path');
var treekill = require('../TreeKill');
var cst = require('../../constants.js');
/**
* Description
* @method exports
* @param {} God
* @return
*/
module.exports = function(God) {
/**
* Description
* @method logAndGenerateError
* @param {} err
* @return NewExpression
*/
God.logAndGenerateError = function(err) {
// Is an Error object
if (err instanceof Error) {
console.trace(err);
return err;
}
// Is a JSON or simple string
console.error(err);
return new Error(err);
};
/**
* Utility functions
* @method getProcesses
* @return MemberExpression
*/
God.getProcesses = function() {
return God.clusters_db;
};
God.getFormatedProcess = function getFormatedProcesses(id) {
if (God.clusters_db[id])
return {
pid : God.clusters_db[id].process.pid,
name : God.clusters_db[id].pm2_env.name,
pm2_env : God.clusters_db[id].pm2_env,
pm_id : God.clusters_db[id].pm2_env.pm_id
};
return {};
};
/**
* Get formated processes
* @method getFormatedProcesses
* @return {Array} formated processes
*/
God.getFormatedProcesses = function getFormatedProcesses() {
var keys = Object.keys(God.clusters_db);
var arr = new Array();
var kl = keys.length;
for (var i = 0; i < kl; i++) {
var key = keys[i];
if (!God.clusters_db[key]) continue;
// Avoid _old type pm_ids
if (isNaN(God.clusters_db[key].pm2_env.pm_id)) continue;
arr.push({
pid : God.clusters_db[key].process.pid,
name : God.clusters_db[key].pm2_env.name,
pm2_env : God.clusters_db[key].pm2_env,
pm_id : God.clusters_db[key].pm2_env.pm_id
})
}
return arr;
};
/**
* Description
* @method findProcessById
* @param {} id
* @return ConditionalExpression
*/
God.findProcessById = function findProcessById(id) {
return God.clusters_db[id] ? God.clusters_db[id] : null;
};
/**
* Description
* @method findByName
* @param {} name
* @return arr
*/
God.findByName = function(name) {
var db = God.clusters_db;
var arr = [];
if (name == 'all') {
for (var key in db) {
// Avoid _old_proc process style
if (typeof(God.clusters_db[key].pm2_env.pm_id) === 'number')
arr.push(db[key]);
}
return arr;
}
for (var key in db) {
if (God.clusters_db[key].pm2_env.name == name ||
God.clusters_db[key].pm2_env.pm_exec_path == p.resolve(name)) {
arr.push(db[key]);
}
}
return arr;
};
/**
* Check if a process is alive in system processes
* Return TRUE if process online
* @method checkProcess
* @param {} pid
* @return
*/
God.checkProcess = function(pid) {
if (!pid) return false;
try {
// Sending 0 signal do not kill the process
process.kill(pid, 0);
return true;
}
catch (err) {
return false;
}
};
/**
* Description
* @method processIsDead
* @param {} pid
* @param {} cb
* @return Literal
*/
God.processIsDead = function(pid, pm2_env, cb, sigkill) {
if (!pid) return cb({type : 'param:missing', msg : 'no pid passed'});
var timeout = null;
var kill_timeout = (pm2_env && pm2_env.kill_timeout) ? pm2_env.kill_timeout : cst.KILL_TIMEOUT;
var mode = pm2_env.exec_mode;
var timer = setInterval(function() {
if (God.checkProcess(pid) === false) {
console.log('pid=%d msg=process killed', pid);
clearTimeout(timeout);
clearInterval(timer);
return cb(null, true);
}
console.log('pid=%d msg=failed to kill - retrying in %dms', pid, pm2_env.kill_retry_time);
return false;
}, pm2_env.kill_retry_time);
timeout = setTimeout(function() {
clearInterval(timer);
if (sigkill) {
console.log('Process with pid %d could not be killed', pid);
return cb({type : 'timeout', msg : 'timeout'});
}
else {
console.log('Process with pid %d still alive after %sms, sending it SIGKILL now...', pid, kill_timeout);
if (pm2_env.treekill !== true) {
try {
process.kill(parseInt(pid), 'SIGKILL');
} catch(e) {
console.error('[SimpleKill][SIGKILL] %s pid can not be killed', pid, e.stack, e.message);
}
return God.processIsDead(pid, pm2_env, cb, true);
}
else {
treekill(parseInt(pid), 'SIGKILL', function(err) {
return God.processIsDead(pid, pm2_env, cb, true);
});
}
}
}, kill_timeout);
return false;
};
/**
* Description
* @method killProcess
* @param int pid
* @param Object pm2_env
* @param function cb
* @return CallExpression
*/
God.killProcess = function(pid, pm2_env, cb) {
if (!pid) return cb({msg : 'no pid passed or null'});
if (typeof(pm2_env.pm_id) === 'number' &&
(cst.KILL_USE_MESSAGE || pm2_env.shutdown_with_message == true)) {
var proc = God.clusters_db[pm2_env.pm_id];
if (proc && proc.send) {
try {
proc.send('shutdown');
} catch (e) {
console.error(`[AppKill] Cannot send "shutdown" message to ${pid}`)
console.error(e.stack, e.message)
}
return God.processIsDead(pid, pm2_env, cb);
}
else {
console.log(`[AppKill] ${pid} pid cannot be notified with send()`)
}
}
if (pm2_env.treekill !== true) {
try {
process.kill(parseInt(pid), cst.KILL_SIGNAL);
} catch(e) {
console.error('[SimpleKill] %s pid can not be killed', pid, e.stack, e.message);
}
return God.processIsDead(pid, pm2_env, cb);
}
else {
treekill(parseInt(pid), cst.KILL_SIGNAL, function(err) {
return God.processIsDead(pid, pm2_env, cb);
});
}
};
/**
* Description
* @method getNewId
* @return UpdateExpression
*/
God.getNewId = function() {
return God.next_id++;
};
/**
* When a process is restarted or reloaded reset fields
* to monitor unstable starts
* @method resetState
* @param {} pm2_env
* @return
*/
God.resetState = function(pm2_env) {
pm2_env.created_at = Date.now();
pm2_env.unstable_restarts = 0;
pm2_env.prev_restart_delay = 0;
};
};

240
api.hyungi.net/node_modules/pm2/lib/God/Reload.js generated vendored Normal file
View File

@@ -0,0 +1,240 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
'use strict';
/**
* @file Reload functions related
* @author Alexandre Strzelewicz <as@unitech.io>
* @project PM2
*/
var cst = require('../../constants.js');
var Utility = require('../Utility.js');
/**
* softReload will wait permission from process to exit
* @method softReload
* @param {} God
* @param {} id
* @param {} cb
* @return Literal
*/
function softReload(God, id, cb) {
var t_key = '_old_' + id;
// Move old worker to tmp id
God.clusters_db[t_key] = God.clusters_db[id];
delete God.clusters_db[id];
var old_worker = God.clusters_db[t_key];
// Deep copy
var new_env = Utility.clone(old_worker.pm2_env);
// Reset created_at and unstable_restarts
God.resetState(new_env);
new_env.restart_time += 1;
old_worker.pm2_env.pm_id = t_key;
old_worker.pm_id = t_key;
God.executeApp(new_env, function(err, new_worker) {
if (err) return cb(err);
var timer = null;
var onListen = function () {
clearTimeout(timer);
softCleanDeleteProcess();
console.log('-softReload- New worker listening');
};
// Bind to know when the new process is up
new_worker.once('listening', onListen);
timer = setTimeout(function() {
new_worker.removeListener('listening', onListen);
softCleanDeleteProcess();
}, new_env.listen_timeout || cst.GRACEFUL_LISTEN_TIMEOUT);
// Remove old worker properly
var softCleanDeleteProcess = function () {
var cleanUp = function () {
clearTimeout(timer);
console.log('-softReload- Old worker disconnected');
return God.deleteProcessId(t_key, cb);
};
old_worker.once('disconnect', cleanUp);
try {
if (old_worker.state != 'dead' && old_worker.state != 'disconnected')
old_worker.send && old_worker.send('shutdown');
else {
clearTimeout(timer);
console.error('Worker %d is already disconnected', old_worker.pm2_env.pm_id);
return God.deleteProcessId(t_key, cb);
}
} catch(e) {
clearTimeout(timer);
console.error('Worker %d is already disconnected', old_worker.pm2_env.pm_id);
return God.deleteProcessId(t_key, cb);
}
timer = setTimeout(function () {
old_worker.removeListener('disconnect', cleanUp);
return God.deleteProcessId(t_key, cb);
}, cst.GRACEFUL_TIMEOUT);
return false;
};
return false;
});
return false;
};
/**
* hardReload will reload without waiting permission from process
* @method hardReload
* @param {} God
* @param {} id
* @param {} cb
* @return Literal
*/
function hardReload(God, id, wait_msg, cb) {
var t_key = '_old_' + id;
// Move old worker to tmp id
God.clusters_db[t_key] = God.clusters_db[id];
delete God.clusters_db[id];
var old_worker = God.clusters_db[t_key];
// Deep copy
var new_env = Utility.clone(old_worker.pm2_env);
new_env.restart_time += 1;
// Reset created_at and unstable_restarts
God.resetState(new_env);
old_worker.pm2_env.pm_id = t_key;
old_worker.pm_id = t_key;
var timer = null;
var readySignalSent = false;
var onListen = function () {
clearTimeout(timer);
readySignalSent = true;
console.log('-reload- New worker listening');
return God.deleteProcessId(t_key, cb);
};
var listener = function (packet) {
if (packet.raw === 'ready' &&
packet.process.name === old_worker.pm2_env.name &&
packet.process.pm_id === id) {
God.bus.removeListener('process:msg', listener);
return onListen();
}
};
if (wait_msg !== 'listening') {
God.bus.on('process:msg', listener);
}
God.executeApp(new_env, function(err, new_worker) {
if (err) return cb(err);
// Bind to know when the new process is up
if (wait_msg === 'listening') {
new_worker.once('listening', onListen);
}
timer = setTimeout(function() {
if (readySignalSent) {
return;
}
if (wait_msg === 'listening')
new_worker.removeListener(wait_msg, onListen);
else
God.bus.removeListener('process:msg', listener);
return God.deleteProcessId(t_key, cb);
}, new_env.listen_timeout || cst.GRACEFUL_LISTEN_TIMEOUT);
return false;
});
return false;
};
/**
* Description
* @method exports
* @param {} God
* @return
*/
module.exports = function(God) {
/**
* Reload
* @method softReloadProcessId
* @param {} id
* @param {} cb
* @return CallExpression
*/
God.softReloadProcessId = function(opts, cb) {
var id = opts.id;
var env = opts.env || {};
if (!(id in God.clusters_db))
return cb(new Error(`pm_id ${id} not available in ${id}`));
if (God.clusters_db[id].pm2_env.status == cst.ONLINE_STATUS &&
God.clusters_db[id].pm2_env.exec_mode == 'cluster_mode' &&
!God.clusters_db[id].pm2_env.wait_ready) {
Utility.extend(God.clusters_db[id].pm2_env.env, opts.env);
Utility.extendExtraConfig(God.clusters_db[id], opts);
return softReload(God, id, cb);
}
else {
console.log('Process %s in a stopped status, starting it', id);
return God.restartProcessId(opts, cb);
}
};
/**
* Reload
* @method reloadProcessId
* @param {} id
* @param {} cb
* @return CallExpression
*/
God.reloadProcessId = function(opts, cb) {
var id = opts.id;
var env = opts.env || {};
if (!(id in God.clusters_db))
return cb(new Error('PM2 ID unknown'));
if (God.clusters_db[id].pm2_env.status == cst.ONLINE_STATUS &&
God.clusters_db[id].pm2_env.exec_mode == 'cluster_mode') {
Utility.extend(God.clusters_db[id].pm2_env.env, opts.env);
Utility.extendExtraConfig(God.clusters_db[id], opts);
var wait_msg = God.clusters_db[id].pm2_env.wait_ready ? 'ready' : 'listening';
return hardReload(God, id, wait_msg, cb);
}
else {
console.log('Process %s in a stopped status, starting it', id);
return God.restartProcessId(opts, cb);
}
};
};