├── pm2
├── LICENSE
├── bin
│ ├── pm2-dev
│ ├── pm2-docker
│ └── pm2-runtime
├── .gitattributes
├── lib
│ ├── templates
│ │ ├── ecosystem-simple.tpl
│ │ ├── Dockerfiles
│ │ │ ├── Dockerfile-nodejs.tpl
│ │ │ ├── Dockerfile-java.tpl
│ │ │ └── Dockerfile-ruby.tpl
│ │ ├── logrotate.d
│ │ │ └── pm2
│ │ ├── init-scripts
│ │ │ ├── systemd.tpl
│ │ │ ├── systemd-online.tpl
│ │ │ ├── rcd.tpl
│ │ │ ├── launchd.tpl
│ │ │ ├── openrc.tpl
│ │ │ ├── pm2-init-amazon.sh
│ │ │ └── upstart.tpl
│ │ └── ecosystem.tpl
│ ├── API
│ │ ├── interpreter.json
│ │ ├── Keymetrics
│ │ │ ├── motd
│ │ │ └── kmapi.js
│ │ ├── Spinner.js
│ │ ├── schema.json
│ │ ├── Deploy.js
│ │ ├── Interaction.js
│ │ ├── Modules
│ │ │ ├── Modularizerv1.js
│ │ │ └── Modules.js
│ │ └── Monit.js
│ ├── motd.update
│ ├── tools
│ │ ├── IsAbsolute.js
│ │ ├── open.js
│ │ ├── fmt.js
│ │ ├── promise.min.js
│ │ └── isbinaryfile.js
│ ├── Interactor
│ │ ├── internal-ip.js
│ │ ├── RemoteActions
│ │ │ ├── ScopedExecution.js
│ │ │ └── CustomActions.js
│ │ ├── Cipher.js
│ │ ├── WatchDog.js
│ │ ├── HttpRequest.js
│ │ ├── Password.js
│ │ ├── pm2-interface.js
│ │ ├── Filter.js
│ │ └── ReverseInteractor.js
│ ├── Event.js
│ ├── completion.sh
│ ├── motd
│ ├── HttpInterface.js
│ ├── ProcessContainerFork.js
│ ├── TreeKill.js
│ ├── binaries
│ │ ├── Runtime.js
│ │ ├── DevCLI.js
│ │ └── Runtime4Docker.js
│ ├── Watcher.js
│ ├── God
│ │ ├── ClusterMode.js
│ │ └── Reload.js
│ └── Worker.js
├── index.js
├── .travis.yml
├── types
│ └── tsconfig.json
├── Makefile
├── changelogTemplate.md
├── .drone.yml
├── .changelogrc
├── CONTRIBUTING.md
├── paths.js
├── constants.js
└── package.json
├── pm2-app
├── pm2
├── startDaemon
├── package.json
├── app.json
├── app2.json
├── pm2_connect.js
├── app.js
└── app2.js
├── test-script
├── nodeshell.js
├── os.js
├── spawn
├── mainProcess.js
└── node-version.js
├── .gitignore
├── spawn
├── ProcessContainer.js
├── unit.js
├── spawn.js
├── app.js
└── processContainerFork.js
├── cluster
├── ProcessContainer.js
├── cluster1-unit.js
├── cluster2-unit.js
├── cluster3.js
├── cluster.js
├── cluster2.js
└── app.js
├── startServer.sh
├── package.json
├── tagg.js
├── npm-debug.log.2939786434
├── v8profiler
└── index.js
├── axon
├── pub-emitter
│ ├── axon.js
│ └── axon-client.js
├── req
│ ├── req.js
│ └── rep.js
└── pm2-axon
│ ├── req.js
│ └── rep.js
├── node-require
├── b.js
└── a.js
├── eventeniiter2
└── index.js
├── demain
└── domain.js
└── vizion
└── index.js
/pm2/LICENSE:
--------------------------------------------------------------------------------
1 | GNU-AGPL-3.0.txt
2 |
--------------------------------------------------------------------------------
/pm2-app/pm2:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | DEBUG=pm2-read ../pm2/bin/pm2 $*
--------------------------------------------------------------------------------
/pm2-app/startDaemon:
--------------------------------------------------------------------------------
1 | DEBUG=pm2-read node ../pm2/lib/Daemon.js
2 |
--------------------------------------------------------------------------------
/test-script/nodeshell.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | console.log(process.pid)
4 |
--------------------------------------------------------------------------------
/pm2/bin/pm2-dev:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require('../lib/binaries/DevCLI.js');
4 |
--------------------------------------------------------------------------------
/pm2/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.sh eol=lf
3 | bin/** eol=lf
4 | test/fixtures/** eol=lf
5 |
--------------------------------------------------------------------------------
/pm2/bin/pm2-docker:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require('../lib/binaries/Runtime4Docker.js');
4 |
--------------------------------------------------------------------------------
/pm2/bin/pm2-runtime:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require('../lib/binaries/Runtime4Docker.js');
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | node_modules/*
3 | .idea
4 | .cache
5 | npm-debug.log
6 | .DS_Store
7 | .DS_Store/*
--------------------------------------------------------------------------------
/test-script/os.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/10.
3 | */
4 | let os = require('os');
5 |
6 |
7 | console.log(os.cpus().length)
--------------------------------------------------------------------------------
/pm2/lib/templates/ecosystem-simple.tpl:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | apps : [{
3 | name : "app1",
4 | script : "./app.js"
5 | }]
6 | }
7 |
--------------------------------------------------------------------------------
/pm2/lib/templates/Dockerfiles/Dockerfile-nodejs.tpl:
--------------------------------------------------------------------------------
1 | FROM keymetrics/pm2:latest
2 |
3 | RUN mkdir -p /var/app
4 |
5 | WORKDIR /var/app
6 |
7 | COPY ./package.json /var/app
8 | RUN npm install
9 |
--------------------------------------------------------------------------------
/pm2/lib/templates/Dockerfiles/Dockerfile-java.tpl:
--------------------------------------------------------------------------------
1 | FROM anapsix/alpine-java:latest
2 |
3 | RUN apk update && apk add git && rm -rf /var/cache/apk/*
4 | RUN npm install pm2@next -g
5 | RUN mkdir -p /var/app
6 |
7 | WORKDIR /var/app
8 |
--------------------------------------------------------------------------------
/pm2/lib/templates/Dockerfiles/Dockerfile-ruby.tpl:
--------------------------------------------------------------------------------
1 | FROM anapsix/alpine-ruby:latest
2 |
3 | RUN apk update && apk add git && rm -rf /var/cache/apk/*
4 | RUN npm install pm2@next -g
5 | RUN mkdir -p /var/app
6 |
7 | WORKDIR /var/app
8 |
--------------------------------------------------------------------------------
/pm2-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pm2-app",
3 | "version": "1.0.0",
4 | "description": "",
5 | "scripts": {
6 | "daemon": "./startDaemon",
7 | "app": "./pm2 start app.json"
8 | },
9 | "author": "",
10 | "license": "ISC"
11 | }
12 |
--------------------------------------------------------------------------------
/spawn/ProcessContainer.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 |
3 | let execfile = path.resolve(__dirname,'app.js');
4 | require.main.filename = execfile;
5 | process.title = 'node app.js --name spawn'
6 |
7 | // Resets global paths for require()
8 | require('module')._initPaths();
--------------------------------------------------------------------------------
/cluster/ProcessContainer.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 |
3 | process.title = 'node app.js --name cluster3'
4 |
5 | let execfile = path.resolve(__dirname,'app.js');
6 | require.main.filename = execfile;
7 |
8 | // Resets global paths for require()
9 | require('module')._initPaths();
--------------------------------------------------------------------------------
/pm2/lib/templates/logrotate.d/pm2:
--------------------------------------------------------------------------------
1 | %HOME_PATH%/pm2.log %HOME_PATH%/logs/*.log {
2 | rotate 12
3 | weekly
4 | missingok
5 | notifempty
6 | compress
7 | delaycompress
8 | copytruncate
9 | create 0640 %USER% %USER%
10 | }
11 |
--------------------------------------------------------------------------------
/spawn/unit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/11.
3 | */
4 | const axios = require('axios');
5 |
6 | setInterval(() => {
7 | axios.post('http://localhost:8001').then((res) => {
8 | console.log(res.data);
9 | }).catch((e) => {
10 | console.log(e)
11 | })
12 | }, 500);
--------------------------------------------------------------------------------
/cluster/cluster1-unit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/11.
3 | */
4 | const axios = require('axios');
5 |
6 | setInterval(() => {
7 | axios.post('http://localhost:8000').then((res) => {
8 | console.log(res.data);
9 | }).catch((e) => {
10 | console.log(e)
11 | })
12 | }, 500);
--------------------------------------------------------------------------------
/cluster/cluster2-unit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/11.
3 | */
4 | const axios = require('axios');
5 |
6 | setInterval(() => {
7 | axios.post('http://localhost:8001').then((res) => {
8 | console.log(res.data);
9 | }).catch((e) => {
10 | console.log(e)
11 | })
12 | }, 500);
--------------------------------------------------------------------------------
/pm2/lib/API/interpreter.json:
--------------------------------------------------------------------------------
1 | {
2 | ".sh" : "bash",
3 | ".py" : "python",
4 | ".rb" : "ruby",
5 | ".php" : "php",
6 | ".pl" : "perl",
7 | ".js" : "node",
8 | ".coffee" : "coffee",
9 | ".ls" : "lsc",
10 | ".ts" : "ts-node",
11 | ".tsx" : "ts-node"
12 | }
13 |
--------------------------------------------------------------------------------
/startServer.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | export NVM_DIR="$HOME/.nvm"
3 | [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
4 |
5 | echo 'change node version'
6 | nvm use v8.6.0
7 | echo 'check node version'
8 | node --version
9 | echo 'change work path'
10 | cd /Users/jianchen/workspace/react-webstorm/helloka2
11 | npm start
--------------------------------------------------------------------------------
/test-script/spawn:
--------------------------------------------------------------------------------
1 | const { spawn } = require('child_process');
2 | const ls = spawn('ls', ['-lh', '/usr']);
3 |
4 | ls.stdout.on('data', (data) => {
5 | console.log(`输出:${data}`);
6 | });
7 |
8 | ls.stderr.on('data', (data) => {
9 | console.log(`错误:${data}`);
10 | });
11 |
12 | ls.on('close', (code) => {
13 | console.log(`子进程退出码:${code}`);
14 | });
--------------------------------------------------------------------------------
/pm2/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | process.env.PM2_PROGRAMMATIC = 'true';
8 |
9 | var API = require('./lib/API.js');
10 |
11 | module.exports = new API;
12 | module.exports.custom = API;
13 |
--------------------------------------------------------------------------------
/pm2/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "10"
4 | - "4"
5 | - "6"
6 | - "8"
7 | - "0.12"
8 | os:
9 | - linux
10 | before_install:
11 | - sudo apt-get -qq update
12 | - sudo apt-get install python3
13 | - sudo apt-get install php5-cli
14 | services:
15 | - docker
16 | notifications:
17 | slack: pm2-nodejs:5Lolyw2LMnwy8fziqOGILQxG
18 |
--------------------------------------------------------------------------------
/pm2/lib/API/Keymetrics/motd:
--------------------------------------------------------------------------------
1 | __ __ __ _
2 | / //_/__ __ ______ ___ ___ / /______(_)_________
3 | / ,< / _ \/ / / / __ `__ \/ _ \/ __/ ___/ / ___/ ___/
4 | / /| / __/ /_/ / / / / / / __/ /_/ / / / /__(__ )
5 | /_/ |_\___/\__, /_/ /_/ /_/\___/\__/_/ /_/\___/____/
6 | /____/
7 |
8 | Harden your Node.js application, today
9 |
--------------------------------------------------------------------------------
/pm2-app/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "apps": [{
3 | "name": "app",
4 | "script": "./app.js",
5 | "node_args": "--harmony",
6 | "autorestart": true,
7 | "watch": false,
8 | "ignore_watch" : ["public"],
9 | "exec_interpreter": "node",
10 | "instances" : 3,
11 | "exec_mode": "cluster",
12 | "log_date_format": "YYYY - MM - DD HH: mm Z",
13 | "env": {
14 | "NODE_ENV": "dev"
15 | }
16 | }]
17 | }
18 |
--------------------------------------------------------------------------------
/pm2-app/app2.json:
--------------------------------------------------------------------------------
1 | {
2 | "apps": [{
3 | "name": "app2",
4 | "script": "./app2.js",
5 | "node_args": "--harmony",
6 | "autorestart": true,
7 | "watch": false,
8 | "ignore_watch" : ["public"],
9 | "exec_interpreter": "node",
10 | "instances" : 3,
11 | "exec_mode": "cluster",
12 | "log_date_format": "YYYY - MM - DD HH: mm Z",
13 | "env": {
14 | "NODE_ENV": "dev"
15 | }
16 | }]
17 | }
18 |
--------------------------------------------------------------------------------
/cluster/cluster3.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/11.
3 | */
4 | let cluster = require('cluster');
5 | let http = require('http');
6 | let numCPUs = require("os").cpus().length;
7 | let path = require('path')
8 |
9 | cluster.setupMaster({
10 | windowsHide: true, // windows系统创建的进程关闭其console出来的内容
11 | exec : path.resolve(__dirname,'ProcessContainer.js')
12 | });
13 |
14 | for (let i = 0; i < numCPUs; i++) {
15 | cluster.fork();
16 | }
--------------------------------------------------------------------------------
/cluster/cluster.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/11.
3 | */
4 | let cluster = require('cluster');
5 | let http = require('http');
6 | let numCPUs = require("os").cpus().length;
7 |
8 | if (cluster.isMaster) {
9 | for (let i = 0; i < numCPUs; i++) {
10 | cluster.fork();
11 | }
12 | } else {
13 | http.createServer(function(req, res) {
14 | res.writeHead(200);
15 | res.end('process ' + process.pid + 'port: 8000 says hello!');
16 | }).listen(8000);
17 | }
--------------------------------------------------------------------------------
/cluster/cluster2.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/11.
3 | */
4 | let cluster = require('cluster');
5 | let http = require('http');
6 | let numCPUs = require("os").cpus().length;
7 |
8 | if (cluster.isMaster) {
9 | for (let i = 0; i < numCPUs; i++) {
10 | cluster.fork();
11 | }
12 | } else {
13 | http.createServer(function(req, res) {
14 | res.writeHead(200);
15 | res.end('process ' + process.pid + ' port: 8001 says hello!');
16 | }).listen(8001);
17 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nodeprocess",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "mainProcess.js",
6 | "scripts": {
7 | "start": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "axios": "^0.18.0",
13 | "axon": "2.0.3",
14 | "os": "^0.1.1",
15 | "pm2": "^2.10.3",
16 | "threads_a_gogo": "^0.1.13",
17 | "v8-profiler": "^5.7.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/pm2/types/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "lib": ["es6"],
5 | "noImplicitAny": true,
6 | "noImplicitThis": true,
7 | "strictNullChecks": true,
8 |
9 | // If the library is an external module (uses `export`), this allows your test file to import "mylib" instead of "./index".
10 | // If the library is global (cannot be imported via `import` or `require`), leave this out.
11 | "baseUrl": ".",
12 | "paths": { "mylib": ["."] }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/pm2/lib/templates/init-scripts/systemd.tpl:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=PM2 process manager
3 | Documentation=https://pm2.keymetrics.io/
4 | After=network.target
5 |
6 | [Service]
7 | Type=forking
8 | User=%USER%
9 | LimitNOFILE=infinity
10 | LimitNPROC=infinity
11 | LimitCORE=infinity
12 | Environment=PATH=%NODE_PATH%:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
13 | Environment=PM2_HOME=%HOME_PATH%
14 | PIDFile=%HOME_PATH%/pm2.pid
15 |
16 | ExecStart=%PM2_PATH% resurrect
17 | ExecReload=%PM2_PATH% reload all
18 | ExecStop=%PM2_PATH% kill
19 |
20 | [Install]
21 | WantedBy=multi-user.target
22 |
--------------------------------------------------------------------------------
/pm2/lib/motd.update:
--------------------------------------------------------------------------------
1 |
2 | -------------
3 | __ __ __ _
4 | / //_/__ __ ______ ___ ___ / /______(_)_________
5 | / ,< / _ \/ / / / __ `__ \/ _ \/ __/ ___/ / ___/ ___/
6 | / /| / __/ /_/ / / / / / / __/ /_/ / / / /__(__ )
7 | /_/ |_\___/\__, /_/ /_/ /_/\___/\__/_/ /_/\___/____/
8 | /____/
9 |
10 | Start monitoring your Node.js application today
11 |
12 | $ pm2 monitor
13 |
14 | To know more about the PM2 monitoring solution:
15 |
16 | https://keymetrics.io/
17 |
18 | -------------
19 |
--------------------------------------------------------------------------------
/pm2/Makefile:
--------------------------------------------------------------------------------
1 |
2 | gen_deb:
3 | ./packager/build-dist.sh
4 | ./packager/build-deb.sh
5 |
6 | publish:
7 | ./packager/deploy.sh
8 |
9 | clean:
10 | find node_modules \( -name "example" -o -name "examples" -o -name "docs" -o -name "jsdoc" -o -name "jsdocs" -o -name "test" -o -name "tests" -o -name "*\.md" -o -name "*\.html" -o -name "*\.eot" -o -name "*\.svg" -o -name "*\.woff" \) -print -exec rm -rf {} \;
11 | find node_modules -type d \( -name "example" -o -name "examples" -o -name "docs" -o -name "jsdoc" -o -name "jsdocs" -o -name "test" -o -name "tests" -o -name "*\.md" -o -name "*\.html" -o -name "*\.eot" -o -name "*\.svg" -o -name "*\.woff" \) -print -exec rm -rf {} \;
12 |
--------------------------------------------------------------------------------
/pm2/lib/templates/init-scripts/systemd-online.tpl:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=PM2 process manager
3 | Documentation=https://pm2.keymetrics.io/
4 | After=network.target network-online.target
5 | Wants=network-online.target
6 |
7 | [Service]
8 | Type=forking
9 | User=%USER%
10 | LimitNOFILE=infinity
11 | LimitNPROC=infinity
12 | LimitCORE=infinity
13 | Environment=PATH=%NODE_PATH%:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
14 | Environment=PM2_HOME=%HOME_PATH%
15 | PIDFile=%HOME_PATH%/pm2.pid
16 |
17 | ExecStart=%PM2_PATH% resurrect
18 | ExecReload=%PM2_PATH% reload all
19 | ExecStop=%PM2_PATH% kill
20 |
21 | [Install]
22 | WantedBy=multi-user.target network-online.target
23 |
--------------------------------------------------------------------------------
/pm2/lib/tools/IsAbsolute.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function posix(path) {
4 | return path.charAt(0) === '/';
5 | }
6 |
7 | function win32(path) {
8 | // https://github.com/nodejs/node/blob/b3fcc245fb25539909ef1d5eaa01dbf92e168633/lib/path.js#L56
9 | var splitDeviceRe = /^([a-zA-Z]:|[\\/]{2}[^\\/]+[\\/]+[^\\/]+)?([\\/])?([\s\S]*?)$/;
10 | var result = splitDeviceRe.exec(path);
11 | var device = result[1] || '';
12 | var isUnc = Boolean(device && device.charAt(1) !== ':');
13 |
14 | // UNC paths are always absolute
15 | return Boolean(result[2] || isUnc);
16 | }
17 |
18 | module.exports = process.platform === 'win32' ? win32 : posix;
19 | module.exports.posix = posix;
20 | module.exports.win32 = win32;
21 |
--------------------------------------------------------------------------------
/pm2/lib/templates/init-scripts/rcd.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # PROVIDE: pm2
4 | # REQUIRE: LOGIN
5 | # KEYWORD: shutdown
6 |
7 | . /etc/rc.subr
8 |
9 | name="%SERVICE_NAME%"
10 | rcvar="%SERVICE_NAME%_enable"
11 |
12 | start_cmd="pm2_start"
13 | stop_cmd="pm2_stop"
14 | reload_cmd="pm2_reload"
15 | status_cmd="pm2_status"
16 | extra_commands="reload status"
17 |
18 | pm2()
19 | {
20 | env PATH="$PATH:%NODE_PATH%" PM2_HOME="%HOME_PATH%" su -m "%USER%" -c "%PM2_PATH% $*"
21 | }
22 |
23 | pm2_start()
24 | {
25 | pm2 resurrect
26 | }
27 |
28 | pm2_stop()
29 | {
30 | pm2 kill
31 | }
32 |
33 | pm2_reload()
34 | {
35 | pm2 reload all
36 | }
37 |
38 | pm2_status()
39 | {
40 | pm2 list
41 | }
42 |
43 | load_rc_config $name
44 | run_rc_command "$1"
45 |
--------------------------------------------------------------------------------
/pm2-app/pm2_connect.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/6/11.
3 | */
4 | var pm2 = require('pm2');
5 |
6 | pm2.connect(function(err) {
7 | if (err) {
8 | console.error(err);
9 | process.exit(2);
10 | }
11 |
12 | pm2.start({
13 | script : 'app1.js', // Script to be run
14 | exec_mode : 'cluster', // Allows your app to be clustered
15 | instances : 4, // Optional: Scales your app by 4
16 | max_memory_restart : '100M' // Optional: Restarts your app if it reaches 100Mo
17 | }, function(err, apps) {
18 | pm2.disconnect(); // Disconnects from PM2
19 | console.log('script not found,Disconnects from PM2')
20 | if (err) throw err
21 | });
22 | });
--------------------------------------------------------------------------------
/pm2/changelogTemplate.md:
--------------------------------------------------------------------------------
1 | <% if(logo) { %>
<% } %>
2 | <% if(logo) { %># <%= title %> <% } %>
3 | <% if(intro) { %><%= '\n' %><%= intro %><%= '\n' %><% } %>
4 | <% if(version && (version.name || version.number)) { %>##<% if(version.name){%> <%= version.name %><% } %> <% if(version.date){ %>( <%= version.date %> )<% } %><%= '\n' %><% } %>
5 | <% _.forEach(sections, function(section){
6 | if(section.commitsCount > 0) { %>
7 | ## <%= section.title %>
8 | <% _.forEach(section.commits, function(commit){ %> - <%= printCommit(commit, true) %><% }) %>
9 | <% _.forEach(section.components, function(component){ %> - **<%= component.name %>**
10 | <% _.forEach(component.commits, function(commit){ %> - <%= printCommit(commit, true) %><% }) %>
11 | <% }) %>
12 | <% } %>
13 | <% }) %>
14 |
--------------------------------------------------------------------------------
/pm2/lib/Interactor/internal-ip.js:
--------------------------------------------------------------------------------
1 | var os = require('os');
2 |
3 | var type = {
4 | v4: {
5 | def: '127.0.0.1',
6 | family: 'IPv4'
7 | },
8 | v6: {
9 | def: '::1',
10 | family: 'IPv6'
11 | }
12 | };
13 |
14 | function internalIp(version) {
15 | var options = type[version];
16 | var ret = options.def;
17 | var interfaces = os.networkInterfaces();
18 |
19 | Object.keys(interfaces).forEach(function (el) {
20 | interfaces[el].forEach(function (el2) {
21 | if (!el2.internal && el2.family === options.family) {
22 | ret = el2.address;
23 | }
24 | });
25 | });
26 |
27 | return ret;
28 | }
29 |
30 | function v4() {
31 | return internalIp('v4');
32 | }
33 |
34 | function v6() {
35 | return internalIp('v6');
36 | }
37 |
38 | module.exports = v4;
39 | module.exports.v4 = v4;
40 | module.exports.v6 = v6;
41 |
--------------------------------------------------------------------------------
/tagg.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/10.
3 | */
4 | function fibo (n) {
5 | return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
6 | }
7 | console.time('8 thread');
8 | var numThreads= 8; //创建线程池,最大数为8
9 | var threadPool= require('threads_a_gogo').createPool(numThreads).all.eval(fibo); //为线程池注册程序
10 | var i=8;
11 | var cb = function(err,data){ //注册线程执行完毕的回调函数
12 | console.log(data);
13 | if(!--i){
14 | threadPool.destroy();
15 | console.timeEnd('8 thread');
16 | }
17 | }
18 | threadPool.any.eval('fibo(40)', cb); //开始向线程池中执行fibo(40)这个任务
19 |
20 | threadPool.any.eval('fibo(40)', cb);
21 |
22 | threadPool.any.eval('fibo(40)', cb);
23 |
24 | threadPool.any.eval('fibo(40)', cb);
25 |
26 | threadPool.any.eval('fibo(40)', cb);
27 |
28 | threadPool.any.eval('fibo(40)', cb);
29 |
30 | threadPool.any.eval('fibo(40)', cb);
31 |
32 | threadPool.any.eval('fibo(40)', cb);
--------------------------------------------------------------------------------
/pm2/.drone.yml:
--------------------------------------------------------------------------------
1 | pipeline:
2 | build_rpm:
3 | group: build
4 | image: node:stretch
5 | commands:
6 | - apt-get update
7 | - apt-get install -y git ruby ruby-dev rubygems build-essential fakeroot lintian rpm
8 | - gem install rake
9 | - gem install --no-ri --no-rdoc fpm
10 | - gem install --no-ri --no-rdoc package_cloud
11 | - ./packager/build-dist.sh
12 | - echo $${PACKAGECLOUD_TOKEN} > /root/.packagecloud
13 | - ./packager/build-deb-rpm.sh
14 | - ./packager/publish_deb_rpm.sh
15 | secrets: ['packagecloud_token']
16 | when:
17 | event: tag
18 | build_apk:
19 | group: build
20 | image: keymetrics/alpine-pm2-builder:latest
21 | environment:
22 | - AWS_REPO_BUCKET=alpine-apk.pm2.io
23 | secrets: ['apk_rsa_priv_key', 'apk_rsa_pub_key', 'aws_access_key_id', 'aws_secret_access_key']
24 | when:
25 | event: tag
26 |
--------------------------------------------------------------------------------
/test-script/mainProcess.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/9.
3 | */
4 |
5 | let {execFile} = require('child_process');
6 | //
7 | // const startServer = async () => {
8 | // const {stderr, stdout} = execFile('nvm',['use v8.6.0'], {cwd: '/Users/jianchen/workspace/react-webstorm/helloka2'});
9 | // // const {stderr1, stdout1} = execFile('npm',['start'], {cwd: '/Users/jianchen/workspace/react-webstorm/helloka2'});
10 | // if(stderr) {
11 | // console.log('stderr',stderr);
12 | // return;
13 | // }
14 | // console.log('stdout', stdout)
15 | // }
16 | //
17 | // startServer();
18 |
19 | var ls = execFile('bash',['startServer.sh'], (err, stdout, stderr) => {
20 | if(err){
21 | throw err;
22 | }
23 | console.log(stdout);
24 | console.log(stderr)
25 | execFile('npm',['start'], (err, stdout, stderr) => {
26 | if(err){
27 | throw err;
28 | }
29 | console.log(stdout);
30 | console.log(stderr)
31 | });
32 | });
33 |
34 |
35 |
--------------------------------------------------------------------------------
/spawn/spawn.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jianchen on 2018/5/11.
3 | */
4 | let spawn = require('child_process').spawn
5 | let numCPUs = require("os").cpus().length;
6 | let path = require('path');
7 | var async = require('async')
8 | let cluster = require('cluster')
9 |
10 | let exec_file = path.resolve(__dirname,'processContainerFork.js');
11 | cluster.setupMaster({
12 | windowsHide: true, // windows系统创建的进程关闭其console出来的内容
13 | exec : path.resolve(__dirname,'ProcessContainer.js')
14 | });
15 |
16 |
17 | console.log('exec_file',exec_file)
18 |
19 | async.timesLimit(numCPUs, 1, function (n, next) {
20 | var cspr = spawn('node',['--harmony',exec_file],{
21 | detached:true,
22 | stdio : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core}
23 | });
24 | cspr.process = {};
25 | cspr.process.pid = cspr.pid;
26 | cspr.stderr.on('data',(err) => {
27 | console.log(err.toString())
28 | })
29 | cspr.unref();
30 | next(null, cspr)
31 | })
--------------------------------------------------------------------------------
/pm2/lib/Interactor/RemoteActions/ScopedExecution.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var pm2 = require('../../..');
8 | var domain = require('domain');
9 | var Utility = require('../../Utility.js');
10 |
11 | var d = domain.create();
12 |
13 | d.once('error', function(err) {
14 | process.send(JSON.stringify({err: err.stack, isFinished : true}));
15 | });
16 |
17 | d.run(function() {
18 | var params = JSON.parse(process.env.fork_params);
19 |
20 | console.log('Executing: pm2 %s %s',
21 | params.action,
22 | params.opts.args ? params.opts.args.join(' ') : '');
23 |
24 | pm2.connect(function() {
25 | pm2.remoteV2(params.action, params.opts, function(err, dt) {
26 | process.send(JSON.stringify(Utility.clone({
27 | err: err,
28 | dt: dt,
29 | isFinished : true
30 | })));
31 | pm2.disconnect(process.exit);
32 | });
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/pm2/lib/templates/init-scripts/launchd.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Label
6 | com.PM2
7 | UserName
8 | %USER%
9 | KeepAlive
10 |
11 | ProgramArguments
12 |
13 | /bin/sh
14 | -c
15 | %PM2_PATH% resurrect
16 |
17 | RunAtLoad
18 |
19 | OnDemand
20 |
21 | LaunchOnlyOnce
22 |
23 | EnvironmentVariables
24 |
25 | PATH
26 | %NODE_PATH%
27 | PM2_HOME
28 | %HOME_PATH%
29 |
30 | StandardErrorPath
31 | /tmp/com.PM2.err
32 | StandardOutPath
33 | /tmp/com.PM2.out
34 |
35 |
36 |
--------------------------------------------------------------------------------
/npm-debug.log.2939786434:
--------------------------------------------------------------------------------
1 | 0 info it worked if it ends with ok
2 | 1 verbose cli [ '/Users/jianchen/.nvm/versions/node/v6.11.0/bin/node',
3 | 1 verbose cli '/Users/jianchen/.nvm/versions/node/v6.11.0/bin/npm',
4 | 1 verbose cli 'config',
5 | 1 verbose cli '--loglevel=warn',
6 | 1 verbose cli 'get',
7 | 1 verbose cli 'prefix' ]
8 | 2 info using npm@3.10.10
9 | 3 info using node@v6.11.0
10 | 4 verbose exit [ 0, true ]
11 | 5 verbose stack Error: write EPIPE
12 | 5 verbose stack at exports._errnoException (util.js:1018:11)
13 | 5 verbose stack at WriteWrap.afterWrite (net.js:800:14)
14 | 6 verbose cwd /Users/jianchen/WebstormProjects/nodeprocess
15 | 7 error Darwin 16.7.0
16 | 8 error argv "/Users/jianchen/.nvm/versions/node/v6.11.0/bin/node" "/Users/jianchen/.nvm/versions/node/v6.11.0/bin/npm" "config" "--loglevel=warn" "get" "prefix"
17 | 9 error node v6.11.0
18 | 10 error npm v3.10.10
19 | 11 error code EPIPE
20 | 12 error errno EPIPE
21 | 13 error syscall write
22 | 14 error write EPIPE
23 | 15 error If you need help, you may report this error at:
24 | 15 error
25 | 16 verbose exit [ 1, true ]
26 |
--------------------------------------------------------------------------------
/pm2/lib/Event.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var Utility = require('./Utility.js');
8 |
9 | module.exports = function(God) {
10 |
11 | God.notify = function(action_name, data, manually) {
12 | God.bus.emit('process:event', {
13 | event : action_name,
14 | manually : typeof(manually) == 'undefined' ? false : true,
15 | process : Utility.formatCLU(data),
16 | at : Utility.getDate()
17 | });
18 | };
19 |
20 | God.notifyByProcessId = function(opts, cb) {
21 | if (typeof(opts.id) === 'undefined') { return cb(new Error('process id missing')); }
22 | var proc = God.clusters_db[opts.id];
23 | if (!proc) { return cb(new Error('process id doesnt exists')); }
24 |
25 | God.bus.emit('process:event', {
26 | event : opts.action_name,
27 | manually : typeof(opts.manually) == 'undefined' ? false : true,
28 | process : Utility.formatCLU(proc),
29 | at : Utility.getDate()
30 | });
31 |
32 | process.nextTick(function() {
33 | return cb ? cb(null) : false;
34 | });
35 | return false;
36 | };
37 | };
38 |
--------------------------------------------------------------------------------
/pm2/lib/Interactor/Cipher.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var crypto = require('crypto');
8 |
9 | const CIPHER_ALGORITHM = 'aes256';
10 |
11 | var Cipher = module.exports = {};
12 |
13 | /**
14 | * Description
15 | * @method decipherMessage
16 | * @param {} msg
17 | * @return ret
18 | */
19 | Cipher.decipherMessage = function(msg, key) {
20 | var ret = {};
21 |
22 | try {
23 | var decipher = crypto.createDecipher(CIPHER_ALGORITHM, key);
24 | var decipheredMessage = decipher.update(msg, 'hex', 'utf8');
25 | decipheredMessage += decipher.final('utf8');
26 | ret = JSON.parse(decipheredMessage);
27 | } catch(e) {
28 | return null;
29 | }
30 |
31 | return ret;
32 | }
33 |
34 | /**
35 | * Description
36 | * @method cipherMessage
37 | * @param {} data
38 | * @param {} key
39 | * @return
40 | */
41 | Cipher.cipherMessage = function(data, key) {
42 | try {
43 | var cipher = crypto.createCipher(CIPHER_ALGORITHM, key);
44 | var cipheredData = cipher.update(data, 'utf8', 'hex');
45 | cipheredData += cipher.final('hex');
46 | return cipheredData;
47 | } catch(e) {
48 | return null;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/pm2/lib/completion.sh:
--------------------------------------------------------------------------------
1 | ###-begin-pm2-completion-###
2 | ### credits to npm for the completion file model
3 | #
4 | # Installation: pm2 completion >> ~/.bashrc (or ~/.zshrc)
5 | #
6 |
7 | COMP_WORDBREAKS=${COMP_WORDBREAKS/=/}
8 | COMP_WORDBREAKS=${COMP_WORDBREAKS/@/}
9 | export COMP_WORDBREAKS
10 |
11 | if type complete &>/dev/null; then
12 | _pm2_completion () {
13 | local si="$IFS"
14 | IFS=$'\n' COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \
15 | COMP_LINE="$COMP_LINE" \
16 | COMP_POINT="$COMP_POINT" \
17 | pm2 completion -- "${COMP_WORDS[@]}" \
18 | 2>/dev/null)) || return $?
19 | IFS="$si"
20 | }
21 | complete -o default -F _pm2_completion pm2
22 | elif type compctl &>/dev/null; then
23 | _pm2_completion () {
24 | local cword line point words si
25 | read -Ac words
26 | read -cn cword
27 | let cword-=1
28 | read -l line
29 | read -ln point
30 | si="$IFS"
31 | IFS=$'\n' reply=($(COMP_CWORD="$cword" \
32 | COMP_LINE="$line" \
33 | COMP_POINT="$point" \
34 | pm2 completion -- "${words[@]}" \
35 | 2>/dev/null)) || return $?
36 | IFS="$si"
37 | }
38 | compctl -K _pm2_completion + -f + pm2
39 | fi
40 | ###-end-pm2-completion-###
41 |
--------------------------------------------------------------------------------
/pm2/lib/templates/ecosystem.tpl:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | /**
3 | * Application configuration section
4 | * http://pm2.keymetrics.io/docs/usage/application-declaration/
5 | */
6 | apps : [
7 |
8 | // First application
9 | {
10 | name : 'API',
11 | script : 'app.js',
12 | env: {
13 | COMMON_VARIABLE: 'true'
14 | },
15 | env_production : {
16 | NODE_ENV: 'production'
17 | }
18 | },
19 |
20 | // Second application
21 | {
22 | name : 'WEB',
23 | script : 'web.js'
24 | }
25 | ],
26 |
27 | /**
28 | * Deployment section
29 | * http://pm2.keymetrics.io/docs/usage/deployment/
30 | */
31 | deploy : {
32 | production : {
33 | user : 'node',
34 | host : '212.83.163.1',
35 | ref : 'origin/master',
36 | repo : 'git@github.com:repo.git',
37 | path : '/var/www/production',
38 | 'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production'
39 | },
40 | dev : {
41 | user : 'node',
42 | host : '212.83.163.1',
43 | ref : 'origin/master',
44 | repo : 'git@github.com:repo.git',
45 | path : '/var/www/development',
46 | 'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env dev',
47 | env : {
48 | NODE_ENV: 'dev'
49 | }
50 | }
51 | }
52 | };
53 |
--------------------------------------------------------------------------------
/pm2/lib/motd:
--------------------------------------------------------------------------------
1 |
2 | -------------
3 |
4 | __/\\\\\\\\\\\\\____/\\\\____________/\\\\____/\\\\\\\\\_____
5 | _\/\\\/////////\\\_\/\\\\\\________/\\\\\\__/\\\///////\\\___
6 | _\/\\\_______\/\\\_\/\\\//\\\____/\\\//\\\_\///______\//\\\__
7 | _\/\\\\\\\\\\\\\/__\/\\\\///\\\/\\\/_\/\\\___________/\\\/___
8 | _\/\\\/////////____\/\\\__\///\\\/___\/\\\________/\\\//_____
9 | _\/\\\_____________\/\\\____\///_____\/\\\_____/\\\//________
10 | _\/\\\_____________\/\\\_____________\/\\\___/\\\/___________
11 | _\/\\\_____________\/\\\_____________\/\\\__/\\\\\\\\\\\\\\\_
12 | _\///______________\///______________\///__\///////////////__
13 |
14 |
15 | Community Edition
16 |
17 | Production Process Manager for Node.js applications
18 | with a built-in Load Balancer.
19 |
20 |
21 | Start and Daemonize any application:
22 | $ pm2 start app.js
23 |
24 | Load Balance 4 instances of api.js:
25 | $ pm2 start api.js -i 4
26 |
27 | Monitor in production:
28 | $ pm2 monitor
29 |
30 | Make pm2 auto-boot at server restart:
31 | $ pm2 startup
32 |
33 | To go further checkout:
34 | http://pm2.io/
35 |
36 |
37 | -------------
38 |
--------------------------------------------------------------------------------
/pm2/lib/templates/init-scripts/openrc.tpl:
--------------------------------------------------------------------------------
1 | #!/sbin/openrc-run
2 | # Copyright 2017 the PM2 project authors. All rights reserved.
3 | # Init script automatically generated by pm2 startup
4 |
5 | description="Production process manager for Node.js apps with a built-in load balancer."
6 |
7 | extra_started_commands="reload"
8 |
9 | PM2="%PM2_PATH%"
10 | user=${PM2_USER:-%USER%}
11 | export PM2_HOME=$(eval echo ~${user})"/.pm2/"
12 | # Options for start-stop-daemon (default start function)
13 | command=${PM2}
14 | command_user=${user}
15 | command_args="resurrect"
16 | pidfile=${PM2_HOME}/pm2.pid
17 |
18 | run_pm2_as_user() {
19 | einfo "${PM2} $@"
20 | eval su -l ${user} -c \'${PM2} $@\'
21 | }
22 |
23 | depend() {
24 | need net
25 | need localmount
26 | after bootmisc
27 | }
28 |
29 | start_post() {
30 | if [ "${user}" == "root" ]; then
31 | ewarn "PM2: Better run this daemon as a non root user. To set this user create"
32 | ewarn "PM2: /etc/conf.d/pm2 file and define 'PM2_USER=user' there."
33 | ewarn "PM2: Note user MUST have home directory for PM2 logs/state/etc..."
34 | fi
35 | einfo "PM2: Process Manager started. To start services run:"
36 | einfo "PM2: # su -l ${user} -c '$PM2 start /path/to/app'"
37 | }
38 |
39 | stop() {
40 | ebegin "Stopping PM2 process manager..."
41 | run_pm2_as_user dump
42 | run_pm2_as_user delete all
43 | run_pm2_as_user kill
44 | eend $?
45 | }
46 |
47 | reload() {
48 | ebegin "Reloading pm2"
49 | run_pm2_as_user reload all
50 | eend $?
51 | }
52 |
53 | # vim: ts=4
54 |
--------------------------------------------------------------------------------
/pm2/.changelogrc:
--------------------------------------------------------------------------------
1 | {
2 | "app_name": "",
3 | "logo": "",
4 | "intro": "",
5 | "branch" : "master",
6 | "repo_url": "https://github.com/Unitech/pm2",
7 | "version_name" : "v2.10.3",
8 | "tag": "2.10.2",
9 | "file": "currentTagChangelog.md",
10 | "template": "changelogTemplate.md",
11 | "sections": [
12 | {
13 | "title": "Bug Fixes",
14 | "grep": "^fix"
15 | },
16 | {
17 | "title": "Hot Fixes",
18 | "grep": "^hotfix"
19 | },
20 | {
21 | "title": "Features",
22 | "grep": "^feat"
23 | },
24 | {
25 | "title": "Documentation",
26 | "grep": "^docs"
27 | },
28 | {
29 | "title": "Breaking changes",
30 | "grep": "BREAKING"
31 | },
32 | {
33 | "title": "Refactor",
34 | "grep": "^refactor"
35 | },
36 | {
37 | "title": "Performance improvement",
38 | "grep": "^perf"
39 | },
40 | {
41 | "title": "Style",
42 | "grep": "^style"
43 | },
44 | {
45 | "title": "Test",
46 | "grep": "^test"
47 | },
48 | {
49 | "title": "Chore",
50 | "grep": "^chore"
51 | },
52 | {
53 | "title": "Branchs merged",
54 | "grep": "^Merge branch"
55 | },
56 | {
57 | "title" : "Pull requests merged",
58 | "grep": "^Merge pull request"
59 | }
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/pm2/lib/tools/open.js:
--------------------------------------------------------------------------------
1 | var exec = require('child_process').exec
2 | , path = require('path')
3 | ;
4 |
5 |
6 | /**
7 | * open a file or uri using the default application for the file type.
8 | *
9 | * @return {ChildProcess} - the child process object.
10 | * @param {string} target - the file/uri to open.
11 | * @param {string} appName - (optional) the application to be used to open the
12 | * file (for example, "chrome", "firefox")
13 | * @param {function(Error)} callback - called with null on success, or
14 | * an error object that contains a property 'code' with the exit
15 | * code of the process.
16 | */
17 |
18 | module.exports = open;
19 |
20 | function open(target, appName, callback) {
21 | var opener;
22 |
23 | if (typeof(appName) === 'function') {
24 | callback = appName;
25 | appName = null;
26 | }
27 |
28 | switch (process.platform) {
29 | case 'darwin':
30 | if (appName) {
31 | opener = 'open -a "' + escape(appName) + '"';
32 | } else {
33 | opener = 'open';
34 | }
35 | break;
36 | case 'win32':
37 | // if the first parameter to start is quoted, it uses that as the title
38 | // so we pass a blank title so we can quote the file we are opening
39 | if (appName) {
40 | opener = 'start "" "' + escape(appName) + '"';
41 | } else {
42 | opener = 'start ""';
43 | }
44 | break;
45 | default:
46 | if (appName) {
47 | opener = escape(appName);
48 | } else {
49 | // use Portlands xdg-open everywhere else
50 | opener = path.join(__dirname, './xdg-open');
51 | }
52 | break;
53 | }
54 |
55 | if (process.env.SUDO_USER) {
56 | opener = 'sudo -u ' + process.env.SUDO_USER + ' ' + opener;
57 | }
58 | return exec(opener + ' "' + escape(target) + '"', callback);
59 | }
60 |
61 | function escape(s) {
62 | return s.replace(/"/g, '\\\"');
63 | }
64 |
--------------------------------------------------------------------------------
/pm2/lib/templates/init-scripts/pm2-init-amazon.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # pm2 Process manager for NodeJS
4 | #
5 | # chkconfig: 345 80 20
6 | #
7 | # description: PM2 next gen process manager for Node.js
8 | # processname: pm2
9 | #
10 | ### BEGIN INIT INFO
11 | # Provides: pm2
12 | # Required-Start: $local_fs $remote_fs
13 | # Required-Stop: $local_fs $remote_fs
14 | # Should-Start: $network
15 | # Should-Stop: $network
16 | # Default-Start: 2 3 4 5
17 | # Default-Stop: 0 1 6
18 | # Short-Description: PM2 init script
19 | # Description: PM2 is the next gen process manager for Node.js
20 | ### END INIT INFO
21 |
22 | NAME=pm2
23 | PM2=%PM2_PATH%
24 | USER=%USER%
25 |
26 | export PATH=%NODE_PATH%:$PATH
27 | export PM2_HOME="%HOME_PATH%"
28 |
29 | lockfile="/var/lock/subsys/pm2-init.sh"
30 |
31 | super() {
32 | su - $USER -c "PATH=$PATH; PM2_HOME=$PM2_HOME $*"
33 | }
34 |
35 | start() {
36 | echo "Starting $NAME"
37 | super $PM2 resurrect
38 | retval=$?
39 | [ $retval -eq 0 ] && touch $lockfile
40 | }
41 |
42 | stop() {
43 | echo "Stopping $NAME"
44 | #super $PM2 dump
45 | super $PM2 delete all
46 | super $PM2 kill
47 | rm -f $lockfile
48 | }
49 |
50 | restart() {
51 | echo "Restarting $NAME"
52 | stop
53 | start
54 | }
55 |
56 | reload() {
57 | echo "Reloading $NAME"
58 | super $PM2 reload all
59 | }
60 |
61 | status() {
62 | echo "Status for $NAME:"
63 | super $PM2 list
64 | RETVAL=$?
65 | }
66 |
67 | case "$1" in
68 | start)
69 | start
70 | ;;
71 | stop)
72 | stop
73 | ;;
74 | status)
75 | status
76 | ;;
77 | restart)
78 | restart
79 | ;;
80 | reload)
81 | reload
82 | ;;
83 | *)
84 | echo "Usage: {start|stop|status|restart|reload}"
85 | exit 1
86 | ;;
87 | esac
88 | exit $RETVAL
89 |
--------------------------------------------------------------------------------
/test-script/node-version.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/24.
29 | */
30 | console.log('process.versions.node:',process.versions.node)
--------------------------------------------------------------------------------
/pm2/lib/API/Spinner.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Spinner
3 | * Handle TTY and non-TTY based terminals
4 | */
5 |
6 | var defaultSpinnerString = [
7 | "⠋",
8 | "⠙",
9 | "⠹",
10 | "⠸",
11 | "⠼",
12 | "⠴",
13 | "⠦",
14 | "⠧",
15 | "⠇",
16 | "⠏"
17 | ].join('');
18 |
19 | var InteractiveSpinner = function(textToShow){
20 | this.text = textToShow || '';
21 | this.setSpinnerString(defaultSpinnerString); // use default spinner string
22 | };
23 |
24 | InteractiveSpinner.setDefaultSpinnerString = function(value) {
25 | defaultSpinnerString = value;
26 | };
27 |
28 | InteractiveSpinner.prototype.start = function() {
29 | var current = 0;
30 | var self = this;
31 | this.id = setInterval(function() {
32 | try {
33 | process.stdout.clearLine();
34 | process.stdout.cursorTo(0);
35 | process.stdout.write(self.chars[current] + ' ' + self.text);
36 | current = ++current % self.chars.length;
37 | } catch(e) { // ignore error if term is not tty, just display nothing
38 | }
39 | }, 80);
40 | };
41 |
42 | InteractiveSpinner.prototype.setSpinnerString = function(str) {
43 | this.chars = str.split("");
44 | };
45 |
46 | InteractiveSpinner.prototype.stop = function() {
47 | try {
48 | process.stdout.clearLine();
49 | process.stdout.cursorTo(0);
50 | } catch(e) {}
51 | clearInterval(this.id);
52 | };
53 |
54 | /**
55 | * Display dots if non TTY terminal
56 | */
57 | var StaticSpinner = function(text) {
58 | console.log(text);
59 | }
60 |
61 | StaticSpinner.prototype.start = function() {
62 | this.interval = setInterval(function() {
63 | process.stdout.write('.');
64 | }, 500);
65 | };
66 |
67 | StaticSpinner.prototype.stop = function() {
68 | clearInterval(this.interval);
69 | console.log();
70 | };
71 |
72 | module.exports = function(text) {
73 | if (process.stdout.isTTY)
74 | return new InteractiveSpinner(text);
75 | else
76 | return new StaticSpinner(text);
77 | };
78 |
--------------------------------------------------------------------------------
/v8profiler/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/24.
29 | */
30 | var profiler = require('v8-profiler');
31 | var snapshot1 = profiler.takeSnapshot('cpu');
32 |
33 | console.log(snapshot1)
--------------------------------------------------------------------------------
/cluster/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/6/4.
29 | */
30 | http.createServer(function(req, res) {
31 | res.writeHead(200);
32 | res.end('process ' + process.pid + ' port: 8001 says hello!');
33 | }).listen(8001);
--------------------------------------------------------------------------------
/spawn/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/6/4.
29 | */
30 | let http = require('http');
31 | http.createServer(function(req, res) {
32 | res.writeHead(200);
33 | res.end('process ' + process.pid + ' port: 8001 says hello!');
34 | }).listen(8001);
--------------------------------------------------------------------------------
/pm2-app/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/15.
29 | */
30 | let http = require('http');
31 |
32 | http.createServer(function(req, res) {
33 | res.writeHead(200);
34 | res.end('process ' + process.pid + ' port: 8001 says hello!');
35 | }).listen(8001);
--------------------------------------------------------------------------------
/pm2-app/app2.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/15.
29 | */
30 | let http = require('http');
31 |
32 | http.createServer(function(req, res) {
33 | res.writeHead(200);
34 | res.end('process ' + process.pid + ' port: 8002 says hello!');
35 | }).listen(8002);
--------------------------------------------------------------------------------
/axon/pub-emitter/axon.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/15.
29 | */
30 | var axon = require('axon');
31 | var sock = axon.socket('pub-emitter');
32 |
33 | sock.connect(3000);
34 |
35 | setInterval(function(){
36 | sock.emit('login', { name: 'tobi' });
37 | }, 500);
--------------------------------------------------------------------------------
/node-require/b.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/25.
29 | */
30 | var a = require('./a');
31 | var B = module.exports = function(){
32 | console.log('B')
33 | }
34 | B.prototype.start = () => {
35 | console.log('B.satrt')
36 | }
37 |
38 | var b = new B();
39 | b.start();
--------------------------------------------------------------------------------
/axon/req/req.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/15.
29 | */
30 | var axon = require('pm2-axon');
31 | var sock = axon.socket('req');
32 |
33 | sock.bind(3000);
34 |
35 | setInterval(() => {
36 | sock.send('hello world','chenjianhui',function(res){
37 | console.log(res)
38 | });
39 | },1000)
--------------------------------------------------------------------------------
/node-require/a.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/25.
29 | */
30 | var A = module.exports = function(){
31 | console.log('A');
32 | }
33 |
34 | A.prototype.start = () => {
35 | console.log('A.start');
36 | }
37 |
38 |
39 | setTimeout(()=> {
40 | var a = new A();
41 | a.start();
42 | },500)
--------------------------------------------------------------------------------
/pm2/lib/Interactor/WatchDog.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var PM2 = require('../..');
8 | var debug = require('debug')('interface:watchdog');
9 | var shelljs = require('shelljs');
10 | var csts = require('../../constants');
11 | var path = require('path');
12 |
13 | process.env.PM2_AGENT_ONLINE = true;
14 |
15 | var WatchDog = module.exports = {
16 | start : function(p) {
17 | var self = this;
18 | this.ipm2 = p.conf.ipm2;
19 | this.relaunching = false;
20 | this.pm2_instance = p.conf.pm2_instance;
21 |
22 | /**
23 | * Handle PM2 connection state changes
24 | */
25 | this.ipm2.on('ready', function() {
26 | console.log('[WATCHDOG] Connected to PM2');
27 | self.relaunching = false;
28 | self.autoDump();
29 | });
30 |
31 | console.log('[WATCHDOG] Launching');
32 |
33 | this.ipm2.on('reconnecting', function() {
34 | console.log('[WATCHDOG] PM2 is disconnected - Relaunching PM2');
35 |
36 | if (self.relaunching === true) return console.log('[WATCHDOG] Already relaunching PM2');
37 | self.relaunching = true;
38 |
39 | if (self.dump_interval)
40 | clearInterval(self.dump_interval);
41 |
42 | return WatchDog.resurrect();
43 | });
44 | },
45 | resurrect : function() {
46 | var self = this;
47 |
48 | console.log('[WATCHDOG] Trying to launch PM2 #1');
49 |
50 | shelljs.exec('node ' + path.resolve(__dirname, '../../bin/pm2') + ' resurrect', function() {
51 | setTimeout(function() {
52 | self.relaunching = false;
53 | }, 2500);
54 | });
55 | },
56 | autoDump : function() {
57 | var self = this;
58 |
59 | this.dump_interval = setInterval(function() {
60 | if (self.relaunching == true) return false;
61 |
62 | self.pm2_instance.dump(function(err) {
63 | if (err) return console.error('[WATCHDOG] Error when dumping');
64 | debug('PM2 process list dumped');
65 | return false;
66 | });
67 | }, 5 * 60 * 1000);
68 | }
69 | };
70 |
--------------------------------------------------------------------------------
/pm2/lib/Interactor/HttpRequest.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var http = require('http');
8 | var https = require('https');
9 | var url = require('url')
10 | var debug = require('debug')('interface:http');
11 |
12 | var HttpRequest = module.exports = {};
13 |
14 | HttpRequest.post = function(opts, cb) {
15 | if (!(opts.data && opts.url)) {
16 | return cb({
17 | msg: 'missing parameters',
18 | port: opts.port,
19 | data: opts.data,
20 | url: opts.url
21 | })
22 | }
23 |
24 | if (!opts.port) {
25 | var parsed = url.parse(opts.url)
26 | if (parsed.hostname && parsed.port) {
27 | opts.port = parseInt(parsed.port)
28 | opts.url = parsed.hostname
29 | } else {
30 | opts.port = 443
31 | }
32 | }
33 |
34 | var options = {
35 | hostname: opts.url,
36 | path: '/api/node/verifyPM2',
37 | method: 'POST',
38 | port: opts.port,
39 | rejectUnauthorized: false,
40 | headers: {
41 | 'Content-Type': 'application/json',
42 | 'Content-Length': Buffer.byteLength(JSON.stringify(opts.data))
43 | }
44 | }
45 |
46 | var client = (opts.port === 443) ? https : http;
47 |
48 | var req = client.request(options, function(res){
49 | var dt = '';
50 |
51 | res.on('data', function (chunk) {
52 | dt += chunk;
53 | });
54 |
55 | res.on('end',function(){
56 | try {
57 | cb(null, JSON.parse(dt));
58 | } catch(e) {
59 | cb(e);
60 | }
61 | });
62 |
63 | res.on('error', function(e){
64 | cb(e);
65 | });
66 | });
67 |
68 | req.on('socket', function (socket) {
69 | /**
70 | * Configure request timeout
71 | */
72 | socket.setTimeout(7000);
73 | socket.on('timeout', function() {
74 | debug('Connection timeout when retrieveing PM2 metadata', options);
75 | req.abort();
76 | });
77 | });
78 |
79 | req.on('error', function(e) {
80 | cb(e);
81 | });
82 |
83 | req.write(JSON.stringify(opts.data));
84 |
85 | req.end();
86 | };
87 |
--------------------------------------------------------------------------------
/spawn/processContainerFork.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/6/5.
29 | */
30 | var path = require('path')
31 |
32 | let exec_file = path.resolve(__dirname,'app.js');
33 |
34 | require('module')._load(exec_file, null, true);
35 |
36 | process.title = 'node app.js --name spawn'
37 |
38 | process.mainModule = process.mainModule || {};
39 | process.mainModule.loaded = false;
40 | require.main = process.mainModule;
--------------------------------------------------------------------------------
/axon/pm2-axon/req.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/15.
29 | */
30 | var axon = require('pm2-axon');
31 | var sock = axon.socket('req');
32 | var path = require('path')
33 | var fs = require('fs')
34 | let pub_socket_file = path.resolve('./','sock.file')
35 |
36 | sock.bind(pub_socket_file);
37 |
38 | setInterval(() => {
39 | sock.send('hello world','chenjianhui',function(res){
40 | console.log(res)
41 | });
42 | },1000)
--------------------------------------------------------------------------------
/axon/req/rep.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/15.
29 | */
30 | var axon = require('axon');
31 | var sock = axon.socket('rep');
32 |
33 | sock.connect(3000);
34 |
35 | sock.on('message', function(task, username, reply){
36 | // resize the image
37 | switch (task){
38 | case 'hello world':
39 | reply('hello '+ username);
40 | break;
41 | case 'bye bye':
42 | reply('滚:'+username);
43 | break;
44 | }
45 | });
--------------------------------------------------------------------------------
/axon/pub-emitter/axon-client.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/15.
29 | */
30 | var axon = require('axon');
31 | var sock = axon.socket('sub-emitter');
32 |
33 | sock.bind(3000);
34 |
35 | sock.on('user:login', function(user){
36 | console.log('%s signed in', user.name);
37 | });
38 |
39 | sock.on('user:*', function(action, user){
40 | console.log('%s %s', user.name, action);
41 | });
42 |
43 | sock.on('*', function(event){
44 | console.log(arguments);
45 | });
--------------------------------------------------------------------------------
/pm2/lib/templates/init-scripts/upstart.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | ### BEGIN INIT INFO
3 | # Provides: pm2
4 | # Required-Start: $local_fs $remote_fs $network
5 | # Required-Stop: $local_fs $remote_fs $network
6 | # Default-Start: 2 3 4 5
7 | # Default-Stop: 0 1 6
8 | # Short-Description: PM2 Init script
9 | # Description: PM2 process manager
10 | ### END INIT INFO
11 |
12 | NAME=pm2
13 | PM2=%PM2_PATH%
14 | USER=%USER%
15 | DEFAULT=/etc/default/$NAME
16 |
17 | export PATH=%NODE_PATH%:$PATH
18 | export PM2_HOME="%HOME_PATH%"
19 |
20 | # The following variables can be overwritten in $DEFAULT
21 |
22 | # maximum number of open files
23 | MAX_OPEN_FILES=
24 |
25 | # overwrite settings from default file
26 | if [ -f "$DEFAULT" ]; then
27 | . "$DEFAULT"
28 | fi
29 |
30 | # set maximum open files if set
31 | if [ -n "$MAX_OPEN_FILES" ]; then
32 | ulimit -n $MAX_OPEN_FILES
33 | fi
34 |
35 | get_user_shell() {
36 | local shell=$(getent passwd ${1:-`whoami`} | cut -d: -f7 | sed -e 's/[[:space:]]*$//')
37 |
38 | if [[ $shell == *"/sbin/nologin" ]] || [[ $shell == "/bin/false" ]] || [[ -z "$shell" ]];
39 | then
40 | shell="/bin/bash"
41 | fi
42 |
43 | echo "$shell"
44 | }
45 |
46 | super() {
47 | local shell=$(get_user_shell $USER)
48 | su - $USER -s $shell -c "PATH=$PATH; PM2_HOME=$PM2_HOME $*"
49 | }
50 |
51 | start() {
52 | echo "Starting $NAME"
53 | super $PM2 resurrect
54 | }
55 |
56 | stop() {
57 | super $PM2 kill
58 | }
59 |
60 | restart() {
61 | echo "Restarting $NAME"
62 | stop
63 | start
64 | }
65 |
66 | reload() {
67 | echo "Reloading $NAME"
68 | super $PM2 reload all
69 | }
70 |
71 | status() {
72 | echo "Status for $NAME:"
73 | super $PM2 list
74 | RETVAL=$?
75 | }
76 |
77 | case "$1" in
78 | start)
79 | start
80 | ;;
81 | stop)
82 | stop
83 | ;;
84 | status)
85 | status
86 | ;;
87 | restart)
88 | restart
89 | ;;
90 | reload)
91 | reload
92 | ;;
93 | force-reload)
94 | reload
95 | ;;
96 | *)
97 | echo "Usage: {start|stop|status|restart|reload|force-reload}"
98 | exit 1
99 | ;;
100 | esac
101 | exit $RETVAL
102 |
--------------------------------------------------------------------------------
/axon/pm2-axon/rep.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/15.
29 | */
30 | var axon = require('pm2-axon');
31 | var sock = axon.socket('rep');
32 | var path = require('path')
33 | var fs = require('fs')
34 | let pub_socket_file = path.resolve('./','sock.file')
35 |
36 | sock.connect(pub_socket_file);
37 |
38 | sock.on('message', function(task, username, reply){
39 | // resize the image
40 | switch (task){
41 | case 'hello world':
42 | reply('hello '+ username);
43 | break;
44 | case 'bye bye':
45 | reply('滚:'+username);
46 | break;
47 | }
48 | });
--------------------------------------------------------------------------------
/pm2/lib/tools/fmt.js:
--------------------------------------------------------------------------------
1 | // --------------------------------------------------------------------------------------------------------------------
2 | //
3 | // fmt.js - Command line output formatting.
4 | //
5 | // Copyright (c) 2012 Andrew Chilton - http://chilts.org/
6 | // Written by Andrew Chilton
7 | //
8 | // License: http://opensource.org/licenses/MIT
9 | //
10 | // --------------------------------------------------------------------------------------------------------------------
11 |
12 | var util = require('util');
13 |
14 | // --------------------------------------------------------------------------------------------------------------------
15 |
16 | var sep = '===============================================================================';
17 | var line = '-------------------------------------------------------------------------------';
18 | var field = ' ';
19 |
20 | // --------------------------------------------------------------------------------------------------------------------
21 |
22 | // separator
23 | module.exports.separator = function() {
24 | console.log(sep);
25 | };
26 |
27 | // alias the above
28 | module.exports.sep = module.exports.separator;
29 |
30 | // line
31 | module.exports.line = function() {
32 | console.log(line);
33 | };
34 |
35 | // title
36 | module.exports.title = function(title) {
37 | var out = '--- ' + title + ' ';
38 | out += line.substr(out.length);
39 | console.log(out);
40 | };
41 |
42 | // field
43 | module.exports.field = function(key, value) {
44 | console.log('' + key + field.substr(key.length) + ' : ' + value);
45 | };
46 |
47 | // subfield
48 | module.exports.subfield = function(key, value) {
49 | console.log('- ' + key + field.substr(key.length + 2) + ' : ' + value);
50 | };
51 |
52 | // list item
53 | module.exports.li = function(msg) {
54 | console.log('* ' + msg);
55 | };
56 |
57 | // dump
58 | module.exports.dump = function(data, name) {
59 | if ( name ) {
60 | console.log(name + ' :', util.inspect(data, false, null, true));
61 | }
62 | else {
63 | console.log(util.inspect(data, false, null, true));
64 | }
65 | };
66 |
67 | // msg
68 | module.exports.msg = function(msg) {
69 | console.log(msg);
70 | };
71 |
72 | // --------------------------------------------------------------------------------------------------------------------
73 |
--------------------------------------------------------------------------------
/pm2/lib/tools/promise.min.js:
--------------------------------------------------------------------------------
1 | !function(e){function n(){}function t(e,n){return function(){e.apply(n,arguments)}}function o(e){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],s(e,this)}function i(e,n){for(;3===e._state;)e=e._value;return 0===e._state?void e._deferreds.push(n):(e._handled=!0,void o._immediateFn(function(){var t=1===e._state?n.onFulfilled:n.onRejected;if(null===t)return void(1===e._state?r:u)(n.promise,e._value);var o;try{o=t(e._value)}catch(e){return void u(n.promise,e)}r(n.promise,o)}))}function r(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var i=n.then;if(n instanceof o)return e._state=3,e._value=n,void f(e);if("function"==typeof i)return void s(t(i,n),e)}e._state=1,e._value=n,f(e)}catch(n){u(e,n)}}function u(e,n){e._state=2,e._value=n,f(e)}function f(e){2===e._state&&0===e._deferreds.length&&o._immediateFn(function(){e._handled||o._unhandledRejectionFn(e._value)});for(var n=0,t=e._deferreds.length;n= 0; i--) {
51 | var proc = data.processes[i];
52 |
53 | // Strip important environment variables
54 | if (typeof proc.pm2_env === 'undefined' && typeof proc.pm2_env.env === 'undefined') return;
55 |
56 | delete proc.pm2_env.env;
57 | }
58 | }
59 |
60 | res.statusCode = 200;
61 | res.write(JSON.stringify(data));
62 | return res.end();
63 |
64 | })
65 | }
66 | else {
67 | // 404
68 | res.statusCode = 404;
69 | res.write(JSON.stringify({err : '404'}));
70 | return res.end();
71 | }
72 | }).listen(process.env.PM2_WEB_PORT || cst.WEB_PORT, cst.WEB_IPADDR, function() {
73 | console.log('Web interface listening on %s:%s', cst.WEB_IPADDR, cst.WEB_PORT);
74 | });
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/pm2/lib/Interactor/Password.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | var crypto = require('crypto');
7 |
8 | var saltChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
9 | var saltCharsCount = saltChars.length;
10 |
11 | function generateSalt(len) {
12 | if (typeof len != 'number' || len <= 0 || len !== parseInt(len, 10)) throw new Error('Invalid salt length');
13 | if (crypto.randomBytes) {
14 | return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').substring(0, len);
15 | } else {
16 | for (var i = 0, salt = ''; i < len; i++) {
17 | salt += saltChars.charAt(Math.floor(Math.random() * saltCharsCount));
18 | }
19 | return salt;
20 | }
21 | }
22 |
23 | function generateHash(algorithm, salt, password, iterations) {
24 | iterations = iterations || 1;
25 | try {
26 | var hash = password;
27 | for(var i=0; i_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/24.
29 | */
30 | var EventEmitter2 = require('eventemitter2').EventEmitter2;
31 | var server = new EventEmitter2({
32 |
33 | //
34 | // set this to `true` to use wildcards. It defaults to `false`.
35 | //
36 | wildcard: true,
37 |
38 | //
39 | // the delimiter used to segment namespaces, defaults to `.`.
40 | //
41 | delimiter: '::',
42 |
43 | //
44 | // set this to `true` if you want to emit the newListener event. The default value is `true`.
45 | //
46 | newListener: false,
47 |
48 | //
49 | // the maximum amount of listeners that can be assigned to an event, default 10.
50 | //
51 | maxListeners: 20,
52 |
53 | //
54 | // show event name in memory leak message when more than maximum amount of listeners is assigned, default false
55 | //
56 | verboseMemoryLeak: false
57 | });
58 |
59 | server.on('foo', function(value1, value2) {
60 | console.log(this.event, value1, value2);
61 | });
62 |
63 | server.emit('foo',12,12)
--------------------------------------------------------------------------------
/pm2/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Cloning PM2 development
4 |
5 | ```bash
6 | $ git clone https://github.com/Unitech/pm2.git
7 | $ cd pm2
8 | $ git checkout development
9 | $ npm install
10 | ```
11 |
12 | I recommend having a pm2 alias pointing to the development version to make it easier to use pm2 development:
13 |
14 | ```
15 | $ cd pm2/
16 | $ echo "alias pm2='`pwd`/bin/pm2'" >> ~/.bashrc
17 | ```
18 |
19 | You are now able to use pm2 in dev mode:
20 |
21 | ```
22 | $ pm2 update
23 | $ pm2 ls
24 | ```
25 |
26 | ## Project structure
27 |
28 | ```
29 | .
30 | ├── bin // pm2, pmd, pm2-dev, pm2-docker are there
31 | ├── examples // examples files
32 | ├── lib // source files
33 | ├── pres // presentation files
34 | ├── test // test files
35 | └── types // TypeScript definition files
36 | ```
37 |
38 | ## Modifying the Daemon
39 |
40 | When you modify the Daemon (lib/Daemon.js, lib/God.js, lib/God/*, lib/Watcher.js), you must restart the pm2 Daemon by doing:
41 |
42 | ```
43 | $ pm2 update
44 | ```
45 |
46 | ## Commit rules
47 |
48 | ### Commit message
49 |
50 | A good commit message should describe what changed and why.
51 |
52 | It should :
53 | * contain a short description of the change (preferably 50 characters or less)
54 | * be entirely in lowercase with the exception of proper nouns, acronyms, and the words that refer to code, like function/variable names
55 | * be prefixed with one of the following word
56 | * fix : bug fix
57 | * hotfix : urgent bug fix
58 | * feat : new or updated feature
59 | * docs : documentation updates
60 | * BREAKING : if commit is a breaking change
61 | * refactor : code refactoring (no functional change)
62 | * perf : performance improvement
63 | * style : UX and display updates
64 | * test : tests and CI updates
65 | * chore : updates on build, tools, configuration ...
66 | * Merge branch : when merging branch
67 | * Merge pull request : when merging PR
68 |
69 | ## Tests
70 |
71 | There are two tests type. Programmatic and Behavioral.
72 | The main test command is `npm test`
73 |
74 | ### Programmatic
75 |
76 | Programmatic tests are runned by doing
77 |
78 | ```
79 | $ bash test/pm2_programmatic_tests.sh
80 | ```
81 |
82 | This test files are located in test/programmatic/*
83 |
84 | ### Behavioral
85 |
86 | Behavioral tests are runned by doing:
87 |
88 | ```
89 | $ bash test/pm2_behavior_tests.sh
90 | ```
91 |
92 | This test files are located in test/bash/*
93 |
94 | ## File of interest
95 |
96 | - `$HOME/.pm2` contain all PM2 related files
97 | - `$HOME/.pm2/logs` contain all applications logs
98 | - `$HOME/.pm2/pids` contain all applications pids
99 | - `$HOME/.pm2/pm2.log` PM2 logs
100 | - `$HOME/.pm2/pm2.pid` PM2 pid
101 | - `$HOME/.pm2/rpc.sock` Socket file for remote commands
102 | - `$HOME/.pm2/pub.sock` Socket file for publishable events
103 |
--------------------------------------------------------------------------------
/pm2/lib/tools/isbinaryfile.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | var fs = require('fs');
7 | var path = require("path");
8 | var max_bytes = 512;
9 |
10 | module.exports = function(bytes, size) {
11 | // Read the file with no encoding for raw buffer access.
12 | if (size === undefined) {
13 | var file = bytes;
14 | try {
15 | if(!fs.statSync(file).isFile()) return false;
16 | } catch (err) {
17 | // otherwise continue on
18 | }
19 | var descriptor = fs.openSync(file, 'r');
20 | try {
21 | bytes = new Buffer(max_bytes);
22 | size = fs.readSync(descriptor, bytes, 0, bytes.length, 0);
23 | } finally {
24 | fs.closeSync(descriptor);
25 | }
26 | }
27 | // async version has a function instead of a `size`
28 | else if (typeof size === "function") {
29 | var file = bytes, callback = size;
30 | fs.stat(file, function(err, stat) {
31 | if (err || !stat.isFile()) return callback(null, false);
32 |
33 | fs.open(file, 'r', function(err, descriptor){
34 | if (err) return callback(err);
35 | var bytes = new Buffer(max_bytes);
36 | // Read the file with no encoding for raw buffer access.
37 | fs.read(descriptor, bytes, 0, bytes.length, 0, function(err, size, bytes){
38 | fs.close(descriptor, function(err2){
39 | if (err || err2)
40 | return callback(err || err2);
41 | return callback(null, isBinaryCheck(bytes, size));
42 | });
43 | });
44 | });
45 | });
46 | }
47 |
48 | return isBinaryCheck(bytes, size);
49 | }
50 |
51 | function isBinaryCheck(bytes, size) {
52 | if (size === 0)
53 | return false;
54 |
55 | var suspicious_bytes = 0;
56 | var total_bytes = Math.min(size, max_bytes);
57 |
58 | if (size >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) {
59 | // UTF-8 BOM. This isn't binary.
60 | return false;
61 | }
62 |
63 | for (var i = 0; i < total_bytes; i++) {
64 | if (bytes[i] === 0) { // NULL byte--it's binary!
65 | return true;
66 | }
67 | else if ((bytes[i] < 7 || bytes[i] > 14) && (bytes[i] < 32 || bytes[i] > 127)) {
68 | // UTF-8 detection
69 | if (bytes[i] > 193 && bytes[i] < 224 && i + 1 < total_bytes) {
70 | i++;
71 | if (bytes[i] > 127 && bytes[i] < 192) {
72 | continue;
73 | }
74 | }
75 | else if (bytes[i] > 223 && bytes[i] < 240 && i + 2 < total_bytes) {
76 | i++;
77 | if (bytes[i] > 127 && bytes[i] < 192 && bytes[i + 1] > 127 && bytes[i + 1] < 192) {
78 | i++;
79 | continue;
80 | }
81 | }
82 | suspicious_bytes++;
83 | // Read at least 32 bytes before making a decision
84 | if (i > 32 && (suspicious_bytes * 100) / total_bytes > 10) {
85 | return true;
86 | }
87 | }
88 | }
89 |
90 | if ((suspicious_bytes * 100) / total_bytes > 10) {
91 | return true;
92 | }
93 |
94 | return false;
95 | }
96 |
--------------------------------------------------------------------------------
/pm2/lib/ProcessContainerFork.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | // Inject custom modules
7 | if (process.env.pmx !== 'false') {
8 | require('pmx').init({
9 | transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false,
10 | http: process.env.km_link === 'true' || false,
11 | v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false,
12 | event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false,
13 | deep_metrics: process.env.deep_monitoring === 'true' || false
14 | });
15 | }
16 |
17 | if (typeof(process.env.source_map_support) != "undefined" &&
18 | process.env.source_map_support !== "false") {
19 | require('source-map-support').install();
20 | }
21 |
22 | // Cron restart feature
23 | if (process.env.cron_restart) {
24 | var cron_pattern = process.env.cron_restart;
25 | var cronJob = require('cron').CronJob;
26 | var job = new cronJob({
27 | cronTime: cron_pattern,
28 | onTick: function () {
29 | if (process.connected && process.send) {
30 | process.send({
31 | 'cron_restart': 1
32 | });
33 | } else {
34 | process.exit(0);
35 | }
36 | },
37 | start: false
38 | });
39 | job.start();
40 | }
41 |
42 |
43 | // Rename the process
44 | // 我们在控制台看到的进程名就是在这里命名的
45 | process.title = process.env.PROCESS_TITLE || 'node ' + process.env.pm_exec_path;
46 |
47 | if (process.connected &&
48 | process.send &&
49 | process.versions &&
50 | process.versions.node)
51 | process.send({
52 | 'node_version': process.versions.node
53 | });
54 |
55 | // uid/gid management
56 | if (process.env.uid || process.env.gid) {
57 |
58 | if (typeof(process.env.uid) === 'string') {
59 | process.env.HOME = '/home/' + process.env.uid;
60 | process.env.USER = process.env.uid;
61 | }
62 |
63 | try {
64 | if (process.env.gid)
65 | process.setgid(process.env.gid);
66 | if (process.env.uid){
67 | // If no gid specified - set gid to uid
68 | var new_gid = process.env.gid == null ? process.env.uid : process.env.gid;
69 | process.initgroups(process.env.uid, new_gid);
70 | process.setgid(new_gid);
71 | process.setuid(process.env.uid);
72 | }
73 | } catch(e) {
74 | setTimeout(function() {
75 | console.error('%s on call %s', e.message, e.syscall);
76 | console.error('%s is not accessible', process.env.uid);
77 | return process.exit(1);
78 | }, 100);
79 | }
80 | }
81 |
82 | // Require the real application 真正加载要执行的模块
83 | if (process.env.pm_exec_path)
84 | require('module')._load(process.env.pm_exec_path, null, true);
85 | else
86 | throw new Error('Could not _load() the script');
87 |
88 | // Change some values to make node think that the user's application
89 | // was started directly such as `node app.js`
90 | process.mainModule = process.mainModule || {};
91 | process.mainModule.loaded = false;
92 | require.main = process.mainModule;
93 |
--------------------------------------------------------------------------------
/demain/domain.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/24.
29 | */
30 | /***
31 | * 好忧桑的翻译,凑合着看吧
32 | * Domains provide a way to handle multiple different IO operations as a single group. If any of the event emitters(发出) or callbacks(回收) registered to a domain emit an 'error' event, or throw an error, then the domain object will be notified(通告), rather than losing the context of the error in the process.on('uncaughtException') handler, or causing the program to exit immediately with an error code.
33 | * domain 将系列io操作划分成组的方式进行处理,如果任何事件或者回调注册在domain的error事件上,当错误触发时将会通知到domain的错误处理上,
34 | * 不会被上下文忽略(这种方式之前一般用process.on('uncaughtException')解决)或者引起程序崩溃
35 | */
36 |
37 | var domain = require('domain');
38 | var fs = require('fs');
39 | const d = domain.create();
40 |
41 | function readSomeFile(filename, cb) {
42 | fs.readFile(filename, 'utf8', d.bind((er, data) => {
43 | // if this throws, it will also be passed to the domain
44 | if(er) throw er;
45 | return cb(er, data ? JSON.parse(data) : null);
46 | }));
47 | }
48 |
49 | d.on('error', (er) => {
50 | // an error occurred somewhere.
51 | // if we throw it now, it will crash the program
52 | // with the normal line number and stack message.
53 | console.log(er)
54 | });
55 |
56 | readSomeFile('sd', function (err, data) {
57 | console.log('err', err)
58 | });
59 |
60 | fs.readFile('sd', 'utf8', (err, data) => {
61 | if(err) throw err;
62 | // if this throws, it will also be passed to the domain
63 | return data;
64 | });
65 |
66 |
--------------------------------------------------------------------------------
/pm2/lib/TreeKill.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // From https://raw.githubusercontent.com/pkrumins/node-tree-kill/master/index.js
4 |
5 | var childProcess = require('child_process');
6 | var spawn = childProcess.spawn;
7 | var exec = childProcess.exec;
8 |
9 | module.exports = function (pid, signal, callback) {
10 | var tree = {};
11 | var pidsToProcess = {};
12 | tree[pid] = [];
13 | pidsToProcess[pid] = 1;
14 |
15 | switch (process.platform) {
16 | case 'win32':
17 | exec('taskkill /pid ' + pid + ' /T /F', { windowsHide: true }, callback);
18 | break;
19 | case 'darwin':
20 | buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
21 | return spawn('pgrep', ['-P', parentPid]);
22 | }, function () {
23 | killAll(tree, signal, callback);
24 | });
25 | break;
26 | // case 'sunos':
27 | // buildProcessTreeSunOS(pid, tree, pidsToProcess, function () {
28 | // killAll(tree, signal, callback);
29 | // });
30 | // break;
31 | default: // Linux
32 | buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
33 | return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]);
34 | }, function () {
35 | killAll(tree, signal, callback);
36 | });
37 | break;
38 | }
39 | };
40 |
41 | function killAll (tree, signal, callback) {
42 | var killed = {};
43 | try {
44 | Object.keys(tree).forEach(function (pid) {
45 | tree[pid].forEach(function (pidpid) {
46 | if (!killed[pidpid]) {
47 | killPid(pidpid, signal);
48 | killed[pidpid] = 1;
49 | }
50 | });
51 | if (!killed[pid]) {
52 | killPid(pid, signal);
53 | killed[pid] = 1;
54 | }
55 | });
56 | } catch (err) {
57 | if (callback) {
58 | return callback(err);
59 | } else {
60 | console.error(err);
61 | }
62 | }
63 | if (callback) {
64 | return callback();
65 | }
66 | }
67 |
68 | function killPid(pid, signal) {
69 | try {
70 | process.kill(parseInt(pid, 10), signal);
71 | }
72 | catch (err) {
73 | if (err.code !== 'ESRCH')
74 | console.error(err);
75 | }
76 | }
77 |
78 | function buildProcessTree (parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) {
79 | var ps = spawnChildProcessesList(parentPid);
80 | var allData = '';
81 |
82 | ps.on('error', function(err) {
83 | console.error(err);
84 | });
85 |
86 | if (ps.stdout) {
87 | ps.stdout.on('data', function (data) {
88 | data = data.toString('ascii');
89 | allData += data;
90 | });
91 | }
92 |
93 | var onClose = function (code) {
94 | delete pidsToProcess[parentPid];
95 |
96 | if (code !== 0) {
97 | // no more parent processes
98 | if (Object.keys(pidsToProcess).length == 0) {
99 | cb();
100 | }
101 | return;
102 | }
103 | var pids = allData.match(/\d+/g) || [];
104 | if (pids.length === 0)
105 | return cb();
106 |
107 | pids.forEach(function (pid) {
108 | pid = parseInt(pid, 10);
109 | tree[parentPid].push(pid);
110 | tree[pid] = [];
111 | pidsToProcess[pid] = 1;
112 | buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb);
113 | });
114 | };
115 |
116 | ps.on('close', onClose);
117 | }
118 |
--------------------------------------------------------------------------------
/pm2/paths.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var debug = require('debug')('pm2:paths');
8 | var p = require('path');
9 | var readLog = require('debug')('pm2-read');
10 |
11 | function getDefaultPM2Home() {
12 | var PM2_ROOT_PATH;
13 |
14 | if (process.env.PM2_HOME)
15 | PM2_ROOT_PATH = process.env.PM2_HOME;
16 | else if (process.env.HOME && !process.env.HOMEPATH)
17 | PM2_ROOT_PATH = p.resolve(process.env.HOME, '.pm2');
18 | else if (process.env.HOME || process.env.HOMEPATH)
19 | PM2_ROOT_PATH = p.resolve(process.env.HOMEDRIVE, process.env.HOME || process.env.HOMEPATH, '.pm2');
20 | else {
21 | console.error('[PM2][Initialization] Environment variable HOME (Linux) or HOMEPATH (Windows) are not set!');
22 | console.error('[PM2][Initialization] Defaulting to /etc/.pm2');
23 | PM2_ROOT_PATH = p.resolve('/etc', '.pm2');
24 | }
25 |
26 | debug('pm2 home resolved to %s', PM2_ROOT_PATH, process.env.HOME);
27 | return PM2_ROOT_PATH;
28 | }
29 |
30 | module.exports = function(PM2_HOME) {
31 | if (!PM2_HOME)
32 | PM2_HOME = getDefaultPM2Home()
33 | readLog('PM2_HOME: %s',PM2_HOME)
34 | var pm2_file_stucture = {
35 | PM2_HOME : PM2_HOME,
36 | PM2_ROOT_PATH : PM2_HOME,
37 |
38 | PM2_CONF_FILE : p.resolve(PM2_HOME, 'conf.js'),
39 | PM2_MODULE_CONF_FILE : p.resolve(PM2_HOME, 'module_conf.json'),
40 |
41 | PM2_LOG_FILE_PATH : p.resolve(PM2_HOME, 'pm2.log'),
42 | PM2_PID_FILE_PATH : p.resolve(PM2_HOME, 'pm2.pid'),
43 |
44 | PM2_RELOAD_LOCKFILE : p.resolve(PM2_HOME, 'reload.lock'),
45 |
46 | DEFAULT_PID_PATH : p.resolve(PM2_HOME, 'pids'),
47 | DEFAULT_LOG_PATH : p.resolve(PM2_HOME, 'logs'),
48 | DEFAULT_MODULE_PATH : p.resolve(PM2_HOME, 'modules'),
49 | KM_ACCESS_TOKEN : p.resolve(PM2_HOME, 'km-access-token'),
50 | DUMP_FILE_PATH : p.resolve(PM2_HOME, 'dump.pm2'),
51 | DUMP_BACKUP_FILE_PATH : p.resolve(PM2_HOME, 'dump.pm2.bak'),
52 |
53 | DAEMON_RPC_PORT : p.resolve(PM2_HOME, 'rpc.sock'),
54 | DAEMON_PUB_PORT : p.resolve(PM2_HOME, 'pub.sock'),
55 | INTERACTOR_RPC_PORT : p.resolve(PM2_HOME, 'interactor.sock'),
56 |
57 | INTERACTOR_LOG_FILE_PATH : p.resolve(PM2_HOME, 'agent.log'),
58 | INTERACTOR_PID_PATH : p.resolve(PM2_HOME, 'agent.pid'),
59 | INTERACTION_CONF : p.resolve(PM2_HOME, 'agent.json5')
60 | };
61 |
62 | // allow overide of file paths via environnement
63 | var paths = Object.keys(pm2_file_stucture);
64 | paths.forEach(function (key) {
65 | var envKey = key.indexOf('PM2_') > -1 ? key : 'PM2_' + key;
66 | if (process.env[envKey] && key !== 'PM2_HOME' && key !== 'PM2_ROOT_PATH') {
67 | pm2_file_stucture[key] = process.env[envKey];
68 | }
69 | });
70 |
71 | if (process.platform === 'win32' ||
72 | process.platform === 'win64') {
73 | //@todo instead of static unique rpc/pub file custom with PM2_HOME or UID
74 | pm2_file_stucture.DAEMON_RPC_PORT = '\\\\.\\pipe\\rpc.sock';
75 | pm2_file_stucture.DAEMON_PUB_PORT = '\\\\.\\pipe\\pub.sock';
76 | pm2_file_stucture.INTERACTOR_RPC_PORT = '\\\\.\\pipe\\interactor.sock';
77 | }
78 |
79 | return pm2_file_stucture;
80 | };
81 |
--------------------------------------------------------------------------------
/pm2/lib/binaries/Runtime.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | var commander = require('commander');
5 |
6 | var debug = require('debug')('pm2:cli');
7 | var PM2 = require('../..');
8 | var Log = require('../../lib/API/Log');
9 | var cst = require('../../constants.js');
10 | var pkg = require('../../package.json');
11 | var path = require('path');
12 |
13 | var pm2;
14 |
15 | // Do not print banner
16 | process.env.PM2_DISCRETE_MODE = true;
17 |
18 | commander.version(pkg.version)
19 | .description('pm2-runtime is an automatic pmx injection that runs in simulated no-daemon environment')
20 | .option('--auto-manage', 'keep application online after command exit')
21 | .option('--fast-boot', 'boot app faster by keeping pm2 runtime online in background (effective at second exit/start)')
22 | .option('--web [port]', 'launch process web api on [port] default to 9615')
23 | .option('--secret [key]', 'keymetrics secret key')
24 | .option('--public [key]', 'keymetrics public key')
25 | .option('--machine-name [name]', 'keymetrics machine name')
26 | .option('--env [name]', 'select env_[name] env variables in process config file')
27 | .option('--watch', 'Watch and Restart')
28 | .option('-i --instances ', 'launch [number] instances with load-balancer')
29 | .usage('pm2-runtime app.js');
30 |
31 | commander.command('*')
32 | .action(function(cmd){
33 | pm2 = new PM2.custom({
34 | pm2_home : path.join(process.env.HOME, '.pm3'),
35 | secret_key : process.env.KEYMETRICS_SECRET || commander.secret,
36 | public_key : process.env.KEYMETRICS_PUBLIC || commander.public,
37 | machine_name : process.env.INSTANCE_NAME || commander.machineName
38 | });
39 |
40 | pm2.connect(function() {
41 | if (commander.web) {
42 | var port = commander.web === true ? cst.WEB_PORT : commander.web;
43 | pm2.web(port);
44 | }
45 |
46 | pm2.start(cmd, commander, function(err, obj) {
47 | if (process.env.PM2_RUNTIME_DEBUG) {
48 | return pm2.disconnect(function() {});
49 | }
50 |
51 | if (err) {
52 | console.error(err);
53 | return process.exit(1);
54 | }
55 |
56 | var pm_id = obj[0].pm2_env.pm_id;
57 |
58 | if (commander.instances == undefined) {
59 | return pm2.attach(pm_id, function() {
60 | exitPM2();
61 | });
62 | }
63 |
64 | if (commander.json === true)
65 | Log.jsonStream(pm2.Client, pm_id);
66 | else if (commander.format === true)
67 | Log.formatStream(pm2.Client, pm_id, false, 'YYYY-MM-DD-HH:mm:ssZZ');
68 | else
69 | Log.stream(pm2.Client, 'all', true);
70 | });
71 | });
72 | });
73 |
74 | if (process.argv.length == 2) {
75 | commander.outputHelp();
76 | process.exit(1);
77 | }
78 |
79 | process.on('SIGINT', function() {
80 | exitPM2();
81 | });
82 |
83 | process.on('SIGTERM', function() {
84 | exitPM2();
85 | });
86 |
87 | commander.parse(process.argv);
88 |
89 | function exitPM2() {
90 | console.log('Exited at %s', new Date());
91 | if (commander.autoManage)
92 | return process.exit(0);
93 |
94 | if (commander.fastBoot) {
95 | return pm2.delete('all', function() {
96 | process.exit(0);
97 | });
98 | }
99 | pm2.kill(function() {
100 | process.exit(0);
101 | });
102 | }
103 |
--------------------------------------------------------------------------------
/pm2/lib/Watcher.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | var chokidar = require('chokidar');
7 | var p = require('path');
8 | var util = require('util');
9 | var log = require('debug')('pm2:watch');
10 |
11 | module.exports = function ClusterMode(God) {
12 | /**
13 | * Watch folder for changes and restart
14 | * @method watch
15 | * @param {Object} pm2_env pm2 app environnement
16 | * @return MemberExpression
17 | */
18 | God.watch = {};
19 |
20 | God.watch._watchers = {};
21 |
22 | God.watch.enable = function(pm2_env) {
23 | if (God.watch._watchers[pm2_env.pm_id]) {
24 | God.watch._watchers[pm2_env.pm_id].close();
25 | God.watch._watchers[pm2_env.pm_id] = null;
26 | delete God.watch._watchers[pm2_env.pm_id];
27 | }
28 |
29 | log('Initial watch ', pm2_env.watch)
30 |
31 | var watch = pm2_env.watch
32 |
33 | if(typeof watch == 'boolean' || util.isArray(watch) && watch.length === 0)
34 | watch = pm2_env.pm_cwd;
35 |
36 | log('Watching %s', watch);
37 |
38 | var watch_options = {
39 | ignored : pm2_env.ignore_watch || /[\/\\]\.|node_modules/,
40 | persistent : true,
41 | ignoreInitial : true,
42 | cwd: pm2_env.pm_cwd
43 | };
44 |
45 | if (pm2_env.watch_options) {
46 | watch_options = util._extend(watch_options, pm2_env.watch_options);
47 | }
48 |
49 | log('Watch opts', watch_options);
50 |
51 | var watcher = chokidar.watch(watch, watch_options);
52 |
53 | console.log('[Watch] Start watching', pm2_env.name);
54 |
55 | watcher.on('all', function(event, path) {
56 | var self = this;
57 |
58 | if (self.restarting === true) {
59 | log('Already restarting, skipping');
60 | return false;
61 | }
62 |
63 | self.restarting = true;
64 |
65 | console.error('Change detected on path %s for app %s - restarting', path, pm2_env.name);
66 |
67 | God.restartProcessName(pm2_env.name, function(err, list) {
68 | self.restarting = false;
69 |
70 | if (err) {
71 | log('Error while restarting', err);
72 | return false;
73 | }
74 |
75 | return log('Process restarted');
76 | });
77 |
78 | return false;
79 | });
80 |
81 | watcher.on('error', function(e) {
82 | console.error(e.stack || e);
83 | });
84 |
85 | God.watch._watchers[pm2_env.pm_id] = watcher;
86 |
87 | //return God.watch._watchers[pm2_env.name];
88 | },
89 | /**
90 | * Description
91 | * @method close
92 | * @param {} id
93 | * @return
94 | */
95 | God.watch.disableAll = function() {
96 | var watchers = God.watch._watchers;
97 |
98 | console.log('[Watch] PM2 is being killed. Watch is disabled to avoid conflicts');
99 | for (var i in watchers) {
100 | watchers[i].close && watchers[i].close();
101 | watchers.splice(i, 1);
102 | }
103 | },
104 |
105 | God.watch.disable = function(pm2_env) {
106 | var watcher = God.watch._watchers[pm2_env.pm_id]
107 | if (watcher) {
108 | console.log('[Watch] Stop watching', pm2_env.name);
109 | watcher.close();
110 | delete God.watch._watchers[pm2_env.pm_id];
111 | return true;
112 | } else {
113 | return false;
114 | }
115 | }
116 | };
117 |
--------------------------------------------------------------------------------
/pm2/lib/Interactor/RemoteActions/CustomActions.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var debug = require('debug')('interface:driver');
8 | var Cipher = require('../Cipher.js');
9 |
10 | var CustomActions = module.exports = {
11 | /**
12 | * Method to trigger custom actions (axm actions)
13 | */
14 | axmCustomActions : function() {
15 | var self = this;
16 |
17 | this.socket.data('trigger:action', function(raw_msg) {
18 | var msg = {};
19 |
20 | if (process.env.NODE_ENV && (process.env.NODE_ENV == 'test' ||
21 | process.env.NODE_ENV == 'local_test'))
22 | msg = raw_msg;
23 | else
24 | msg = Cipher.decipherMessage(raw_msg, self.conf.SECRET_KEY);
25 |
26 | if (!msg) return console.error('Error while receiving message! #axmCustomActions');
27 |
28 | console.log('New remote action %s triggered for process %s', msg.action_name, msg.process_id);
29 | self.pm2_instance.msgProcess({
30 | id : msg.process_id,
31 | msg : msg.action_name,
32 | opts: msg.opts || null
33 | }, function(err, data) {
34 | if (err) {
35 | return self.socket.send('trigger:action:failure', {
36 | success : false,
37 | err : err.message,
38 | id : msg.process_id,
39 | action_name : msg.action_name
40 | });
41 | }
42 | console.log('[REVERSE INTERACTOR] Message received from AXM for proc_id : %s and action name %s',
43 | msg.process_id, msg.action_name);
44 |
45 | return self.socket.send('trigger:action:success', {
46 | success : true,
47 | id : msg.process_id,
48 | action_name : msg.action_name
49 | });
50 | });
51 | });
52 |
53 | this.socket.data('trigger:scoped_action', function(raw_msg) {
54 | var msg = {};
55 |
56 | if (process.env.NODE_ENV && (process.env.NODE_ENV == 'test' ||
57 | process.env.NODE_ENV == 'local_test'))
58 | msg = raw_msg;
59 | else
60 | msg = Cipher.decipherMessage(raw_msg, self.conf.SECRET_KEY);
61 |
62 | if (!msg) return console.error('Error while receiving message! #axmCustomActions');
63 |
64 | console.log('New SCOPED action %s triggered for process %s', msg.action_name, msg.process.pm_id);
65 |
66 | self.pm2_instance.msgProcess({
67 | id : msg.process.pm_id,
68 | action_name : msg.action_name,
69 | msg : msg.action_name,
70 | opts : msg.options || {},
71 | uuid : msg.uuid
72 | }, function(err, data) {
73 | if (err) {
74 | return self.socket.send('trigger:action:failure', {
75 | success : false,
76 | err : err.message,
77 | id : msg.process.pm_id,
78 | action_name : msg.action_name
79 | });
80 | }
81 | console.log('[REVERSE INTERACTOR] Message received from AXM for proc_id : %s and action name %s',
82 | msg.process_id, msg.action_name);
83 |
84 | return self.socket.send('trigger:action:success', {
85 | success : true,
86 | id : msg.process.pm_id,
87 | action_name : msg.action_name
88 | });
89 | });
90 | });
91 | }
92 | };
93 |
--------------------------------------------------------------------------------
/pm2/lib/Interactor/pm2-interface.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | /**
8 | * Dependencies
9 | */
10 |
11 | var axon = require('pm2-axon');
12 | var cst = require('../../constants.js');
13 | var util = require('util');
14 | var rpc = require('pm2-axon-rpc');
15 | var log = require('debug')('pm2:interface');
16 | var EventEmitter = require('events').EventEmitter;
17 |
18 | /**
19 | * Export with conf
20 | */
21 | module.exports = function(opts){
22 | var sub_port = opts && opts.sub_port || cst.DAEMON_PUB_PORT;
23 | var rpc_port = opts && opts.rpc_port || cst.DAEMON_RPC_PORT;
24 |
25 | return new IPM2(sub_port, rpc_port);
26 | };
27 |
28 | /**
29 | * IPM2, Pm2 Interface
30 | */
31 |
32 | var IPM2 = function(sub_port, rpc_port) {
33 | if (!(this instanceof IPM2)) return new IPM2(sub_port, rpc_port);
34 | var self = this;
35 |
36 | EventEmitter.call(this);
37 |
38 | this.sub_port = sub_port;
39 | this.rpc_port = rpc_port;
40 |
41 |
42 | var sub = axon.socket('sub-emitter');
43 | var sub_sock = this.sub_sock = sub.connect(sub_port);
44 | this.bus = sub;
45 |
46 | var req = axon.socket('req');
47 | var rpc_sock = this.rpc_sock = req.connect(rpc_port);
48 | this.rpc_client = new rpc.Client(req);
49 |
50 | this.rpc = {};
51 |
52 | rpc_sock.on('connect', function() {
53 | log('rpc_sock:ready');
54 | self.emit('rpc_sock:ready');
55 | generateMethods(function() {
56 | self.emit('ready');
57 | });
58 | });
59 |
60 | rpc_sock.on('close', function() {
61 | log('rpc_sock:closed');
62 | self.emit('close');
63 | });
64 |
65 | rpc_sock.on('reconnect attempt', function() {
66 | log('rpc_sock:reconnecting');
67 | self.emit('reconnecting');
68 | });
69 |
70 | sub_sock.on('connect', function() {
71 | log('sub_sock ready');
72 | self.emit('sub_sock:ready');
73 | });
74 |
75 | sub_sock.on('close', function() {
76 | log('sub_sock:closed');
77 | self.emit('closed');
78 | });
79 |
80 | sub_sock.on('reconnect attempt', function() {
81 | log('sub_sock:reconnecting');
82 | self.emit('reconnecting');
83 | });
84 |
85 | /**
86 | * Disconnect socket connections. This will allow Node to exit automatically.
87 | * Further calls to PM2 from this object will throw an error.
88 | */
89 | this.disconnect = function () {
90 | self.sub_sock.close();
91 | self.rpc_sock.close();
92 | };
93 |
94 | /**
95 | * Generate method by requesting exposed methods by PM2
96 | * You can now control/interact with PM2
97 | */
98 | var generateMethods = function(cb) {
99 | log('Requesting and generating RPC methods');
100 | self.rpc_client.methods(function(err, methods) {
101 | Object.keys(methods).forEach(function(key) {
102 | var method_signature, md;
103 | method_signature = md = methods[key];
104 |
105 | log('+-- Creating %s method', md.name);
106 |
107 | (function(name) {
108 | self.rpc[name] = function() {
109 | log(name);
110 | var args = Array.prototype.slice.call(arguments);
111 | args.unshift(name);
112 | self.rpc_client.call.apply(self.rpc_client, args);
113 | };
114 | })(md.name);
115 |
116 | });
117 | return cb();
118 | });
119 | };
120 | };
121 |
122 | util.inherits(IPM2, EventEmitter);
123 |
--------------------------------------------------------------------------------
/pm2/lib/God/ClusterMode.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | 'use strict';
7 |
8 | /**
9 | * @file Cluster execution functions related
10 | * @author Alexandre Strzelewicz
11 | * @project PM2
12 | */
13 | var cluster = require('cluster');
14 | var cst = require('../../constants.js');
15 | var Utility = require('../Utility.js');
16 | var pkg = require('../../package.json');
17 | var readLog = require('debug')('pm2-read');
18 |
19 | /**
20 | * Description
21 | * @method exports
22 | * @param {} God
23 | * @return
24 | */
25 | module.exports = function ClusterMode(God) {
26 |
27 | /**
28 | * For Node apps - Cluster mode
29 | * It will wrap the code and enable load-balancing mode
30 | * @method nodeApp
31 | * @param {} env_copy
32 | * @param {} cb
33 | * @return Literal
34 | */
35 | God.nodeApp = function nodeApp(env_copy, cb){
36 | var clu = null;
37 |
38 | console.log('Starting execution sequence in -cluster mode- for app name:%s id:%s',
39 | env_copy.name,
40 | env_copy.pm_id);
41 |
42 | if (env_copy.node_args && Array.isArray(env_copy.node_args)) {
43 | cluster.settings.execArgv = env_copy.node_args;
44 | }
45 |
46 | env_copy._pm2_version = pkg.version;
47 |
48 | try {
49 | // node.js cluster clients can not receive deep-level objects or arrays in the forked process, e.g.:
50 | // { "args": ["foo", "bar"], "env": { "foo1": "bar1" }} will be parsed to
51 | // { "args": "foo, bar", "env": "[object Object]"}
52 | // So we passing a stringified JSON here.
53 | // readLog('pm2_env环境变量,%s',JSON.stringify(env_copy))
54 | clu = cluster.fork({pm2_env: JSON.stringify(env_copy), windowsHide: true});
55 | } catch(e) {
56 | readLog('pm2_env环境变量')
57 | God.logAndGenerateError(e);
58 | return cb(e);
59 | }
60 |
61 | clu.pm2_env = env_copy;
62 |
63 | /**
64 | * Broadcast message to God
65 | */
66 | clu.on('message', function cluMessage(msg) {
67 | /*********************************
68 | * If you edit this function
69 | * Do the same in ForkMode.js !
70 | *********************************/
71 | if (msg.data && msg.type) {
72 | return God.bus.emit(msg.type ? msg.type : 'process:msg', {
73 | at : Utility.getDate(),
74 | data : msg.data,
75 | process : {
76 | pm_id : clu.pm2_env.pm_id,
77 | name : clu.pm2_env.name,
78 | rev : (clu.pm2_env.versioning && clu.pm2_env.versioning.revision) ? clu.pm2_env.versioning.revision : null
79 | }
80 | });
81 | }
82 | else {
83 |
84 | if (typeof msg == 'object' && 'node_version' in msg) {
85 | clu.pm2_env.node_version = msg.node_version;
86 | return false;
87 | } else if (typeof msg == 'object' && 'cron_restart' in msg) {
88 | return God.restartProcessId({
89 | id : clu.pm2_env.pm_id
90 | }, function() {
91 | console.log('Application %s has been restarted via CRON', clu.pm2_env.name);
92 | });
93 | }
94 |
95 | return God.bus.emit('process:msg', {
96 | at : Utility.getDate(),
97 | raw : msg,
98 | process : {
99 | pm_id : clu.pm2_env.pm_id,
100 | name : clu.pm2_env.name
101 | }
102 | });
103 | }
104 | });
105 |
106 | return cb(null, clu);
107 | };
108 | };
109 |
--------------------------------------------------------------------------------
/pm2/lib/Interactor/Filter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | /**
8 | * @file Filter process and system data to be sent to server
9 | * @author Alexandre Strzelewicz
10 | * @project Interface
11 | */
12 |
13 | var os = require('os');
14 |
15 | var cpu_info = {
16 | number : 0,
17 | info : 'no-data'
18 | };
19 |
20 | try {
21 | cpu_info = {
22 | number : os.cpus().length,
23 | info : os.cpus()[0].model
24 | };
25 | } catch(e) {
26 | }
27 |
28 | var SERVER_META = {
29 | totalMem : os.totalmem(),
30 | hostname : os.hostname(),
31 | type : os.type(),
32 | platform : os.platform(),
33 | arch : os.arch()
34 | };
35 |
36 | var Filter = {};
37 |
38 | Filter.getProcessID = function(machine_name, name, id) {
39 | return machine_name + ':' + name + ':' + id;
40 | };
41 |
42 | Filter.machineSnapshot = function(processes, conf) {
43 | if (!processes) return null;
44 |
45 | var filter_procs = [];
46 |
47 | processes.forEach(function(proc) {
48 | if (proc.pm2_env.pm_id.toString().indexOf('_old_') == -1)
49 | filter_procs.push({
50 | pid : proc.pid,
51 | name : proc.pm2_env.name,
52 | interpreter : proc.pm2_env.exec_interpreter,
53 | restart_time : proc.pm2_env.restart_time,
54 | created_at : proc.pm2_env.created_at,
55 | exec_mode : proc.pm2_env.exec_mode,
56 | watching : proc.pm2_env.watch,
57 | pm_uptime : proc.pm2_env.pm_uptime,
58 | status : proc.pm2_env.status,
59 | pm_id : proc.pm2_env.pm_id,
60 |
61 | cpu : Math.floor(proc.monit.cpu) || 0,
62 | memory : Math.floor(proc.monit.memory) || 0,
63 |
64 | versioning : proc.pm2_env.versioning || null,
65 |
66 | node_env : proc.pm2_env.NODE_ENV || null,
67 |
68 | axm_actions : proc.pm2_env.axm_actions || [],
69 | axm_monitor : proc.pm2_env.axm_monitor || {},
70 | axm_options : proc.pm2_env.axm_options || {},
71 | axm_dynamic : proc.pm2_env.dynamic || {}
72 | });
73 | });
74 |
75 | var node_version = process.version || '';
76 |
77 | if (node_version != '') {
78 | if (node_version.indexOf('v1.') === 0 || node_version.indexOf('v2.') === 0 || node_version.indexOf('v3.') === 0)
79 | node_version = 'iojs ' + node_version;
80 | }
81 | var username = process.env.SUDO_USER || process.env.C9_USER || process.env.LOGNAME ||
82 | process.env.USER || process.env.LNAME || process.env.USERNAME;
83 |
84 | return {
85 | process : filter_procs,
86 | server : {
87 | loadavg : os.loadavg(),
88 | total_mem : SERVER_META.totalMem,
89 | free_mem : os.freemem(),
90 | cpu : cpu_info,
91 | hostname : SERVER_META.hostname,
92 | uptime : os.uptime(),
93 | type : SERVER_META.type,
94 | platform : SERVER_META.platform,
95 | arch : SERVER_META.arch,
96 | user : username,
97 | interaction : conf.REVERSE_INTERACT,
98 | pm2_version : conf.PM2_VERSION,
99 | node_version : node_version
100 | }
101 | };
102 | };
103 |
104 | Filter.monitoring = function(processes, conf) {
105 | if (!processes) return null;
106 |
107 | var filter_procs = {};
108 |
109 | processes.forEach(function(proc) {
110 | filter_procs[Filter.getProcessID(conf.MACHINE_NAME, proc.pm2_env.name,proc.pm2_env.pm_id)] = [
111 | Math.floor(proc.monit.cpu),
112 | Math.floor(proc.monit.memory)
113 | ];
114 | });
115 |
116 | return {
117 | loadavg : os.loadavg(),
118 | total_mem : SERVER_META.totalMem,
119 | free_mem : os.freemem(),
120 | processes : filter_procs
121 | };
122 | };
123 |
124 | module.exports = Filter;
125 |
--------------------------------------------------------------------------------
/pm2/lib/Interactor/ReverseInteractor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var debug = require('debug')('interface:driver');
8 | var nssocket = require('nssocket');
9 | var Url = require('url');
10 | var Cipher = require('./Cipher.js');
11 | var util = require('util');
12 |
13 | var ReverseInteract = {
14 | changeUrl : function(url) {
15 | if (!this.connected) return;
16 | console.log('[REV] Changing URL to %s', url);
17 |
18 | this.network = Url.parse(url);
19 | this.socket.connect(parseInt(this.network.port), this.network.hostname);
20 | this.socket.reconnect();
21 | },
22 | destroy : function() {
23 | this.socket.destroy();
24 | },
25 | reconnect : function() {
26 | console.log('[REV] Reconnecting to %s', this.network.hostname);
27 | this.socket.reconnect();
28 | },
29 | start : function(opts) {
30 | var self = this;
31 |
32 | if (!opts.url)
33 | throw new Error('url not declared');
34 | if (!opts.conf)
35 | throw new Error('Conf not passed to ReverseInteractor');
36 |
37 | this.connected = false;
38 | this.conf = opts.conf;
39 | this.network = Url.parse(opts.url);
40 | this.pm2_instance = opts.conf.pm2_instance;
41 |
42 | this.socket = new nssocket.NsSocket({
43 | type : 'tcp4',
44 | reconnect : true,
45 | retryInterval : 2000,
46 | max : Infinity,
47 | maxListeners : 50
48 | });
49 |
50 | this.socket.on('error', function(e) {
51 | self.connected = false;
52 | console.error('[REV] %s', e.message || e);
53 | });
54 |
55 | this.socket.on('close', function(dt) {
56 | self.connected = false;
57 | });
58 |
59 | this.socket.on('start', function() {
60 | self.connected = true;
61 | opts.conf.rev_con = true;
62 | console.log('[REV] Connected to %s:%s', self.network.hostname, self.network.port);
63 | });
64 |
65 | console.log('[REV] Connecting to %s:%s', this.network.hostname, this.network.port);
66 |
67 | this.socket.connect(parseInt(this.network.port), this.network.hostname);
68 | this.onMessage();
69 | },
70 | /**
71 | * Listening to remote events from Keymetrics
72 | */
73 | onMessage : function() {
74 | if (!this.socket) return console.error('Reverse interaction not initialized');
75 |
76 | /**
77 | * Identify this agent to Keymetrics
78 | * via PUBLIC/PRIVATE key exchange
79 | */
80 | ReverseInteract.introduceToKeymetrics();
81 |
82 | ReverseInteract.axmCustomActions();
83 |
84 | /**
85 | * From Pm2Actions.js
86 | */
87 | ReverseInteract.pm2Actions();
88 |
89 | ReverseInteract.pm2ScopedActions();
90 |
91 | return false;
92 | },
93 | /**
94 | * First method called to identify this agent
95 | */
96 | introduceToKeymetrics : function() {
97 | var self = this;
98 |
99 | this.socket.data('ask', function(raw_msg) {
100 | if (process.env.NODE_ENV && process.env.NODE_ENV == 'test') {
101 | // Dont cipher data in test environment
102 | self.socket.send('ask:rep', {
103 | success : true,
104 | machine_name : self.conf.MACHINE_NAME,
105 | public_key : self.conf.PUBLIC_KEY
106 | });
107 | } else {
108 | var ciphered_data = Cipher.cipherMessage(JSON.stringify({
109 | machine_name : self.conf.MACHINE_NAME
110 | }), self.conf.SECRET_KEY);
111 |
112 | if (!ciphered_data)
113 | return console.error('Got wrong ciphering data %s %s', self.conf.MACHINE_NAME, self.conf.SECRET_KEY);
114 |
115 | self.socket.send('ask:rep', {
116 | data : ciphered_data,
117 | public_key : self.conf.PUBLIC_KEY
118 | });
119 | }
120 | return false;
121 | });
122 | }
123 | };
124 |
125 | util._extend(ReverseInteract, require('./RemoteActions/Pm2Actions.js'));
126 | util._extend(ReverseInteract, require('./RemoteActions/CustomActions.js'));
127 |
128 | module.exports = ReverseInteract;
129 |
--------------------------------------------------------------------------------
/pm2/constants.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var debug = require('debug')('pm2:conf');
8 | var p = require('path');
9 | var util = require('util');
10 | var chalk = require('chalk');
11 | var semver = require('semver');
12 |
13 | /**
14 | * Get PM2 path structure
15 | */
16 | var path_structure = require('./paths.js')(process.env.OVER_HOME);
17 |
18 | /**
19 | * Constants variables used by PM2
20 | */
21 | var csts = {
22 | PREFIX_MSG : chalk.green('[PM2] '),
23 | PREFIX_MSG_ERR : chalk.red('[PM2][ERROR] '),
24 | PREFIX_MSG_MOD : chalk.bold.green('[PM2][Module] '),
25 | PREFIX_MSG_MOD_ERR : chalk.red('[PM2][Module][ERROR] '),
26 | PREFIX_MSG_WARNING : chalk.yellow('[PM2][WARN] '),
27 | PREFIX_MSG_SUCCESS : chalk.cyan('[PM2] '),
28 |
29 | TEMPLATE_FOLDER : p.join(__dirname, 'lib/templates'),
30 |
31 | APP_CONF_DEFAULT_FILE : 'ecosystem.json',
32 | APP_CONF_TPL : 'ecosystem.tpl',
33 | APP_CONF_TPL_SIMPLE : 'ecosystem-simple.tpl',
34 | SAMPLE_CONF_FILE : 'sample-conf.js',
35 | LOGROTATE_SCRIPT : 'logrotate.d/pm2',
36 |
37 | DOCKERFILE_NODEJS : 'Dockerfiles/Dockerfile-nodejs.tpl',
38 | DOCKERFILE_JAVA : 'Dockerfiles/Dockerfile-java.tpl',
39 | DOCKERFILE_RUBY : 'Dockerfiles/Dockerfile-ruby.tpl',
40 |
41 | SUCCESS_EXIT : 0,
42 | ERROR_EXIT : 1,
43 | CODE_UNCAUGHTEXCEPTION : 1,
44 |
45 | IS_WINDOWS : (process.platform === 'win32' || process.platform === 'win64'),
46 | ONLINE_STATUS : 'online',
47 | STOPPED_STATUS : 'stopped',
48 | STOPPING_STATUS : 'stopping',
49 | LAUNCHING_STATUS : 'launching',
50 | ERRORED_STATUS : 'errored',
51 | ONE_LAUNCH_STATUS : 'one-launch-status',
52 |
53 | CLUSTER_MODE_ID : 'cluster_mode',
54 | FORK_MODE_ID : 'fork_mode',
55 |
56 | LOW_MEMORY_ENVIRONMENT : process.env.PM2_OPTIMIZE_MEMORY || false,
57 |
58 | KEYMETRICS_ROOT_URL : process.env.KEYMETRICS_NODE || 'root.keymetrics.io',
59 | KEYMETRICS_BANNER : '../lib/motd',
60 | KEYMETRICS_UPDATE : '../lib/motd.update',
61 | DEFAULT_MODULE_JSON : 'package.json',
62 |
63 | REMOTE_PORT_TCP : isNaN(parseInt(process.env.KEYMETRICS_PUSH_PORT)) ? 80 : parseInt(process.env.KEYMETRICS_PUSH_PORT),
64 | REMOTE_PORT : 41624,
65 | REMOTE_HOST : 's1.keymetrics.io',
66 | SEND_INTERVAL : 1000,
67 | RELOAD_LOCK_TIMEOUT : parseInt(process.env.PM2_RELOAD_LOCK_TIMEOUT) || 30000,
68 | GRACEFUL_TIMEOUT : parseInt(process.env.PM2_GRACEFUL_TIMEOUT) || 8000,
69 | GRACEFUL_LISTEN_TIMEOUT : parseInt(process.env.PM2_GRACEFUL_LISTEN_TIMEOUT) || 3000,
70 | LOGS_BUFFER_SIZE : 8,
71 | CONTEXT_ON_ERROR : 2,
72 | AGGREGATION_DURATION : process.env.PM2_DEBUG || process.env.NODE_ENV === 'local_test' || process.env.NODE_ENV === 'development' ? 3000 : 5 * 60000,
73 | TRACE_FLUSH_INTERVAL : process.env.PM2_DEBUG || process.env.NODE_ENV === 'local_test' ? 1000 : 60000,
74 |
75 | // Concurrent actions when doing start/restart/reload
76 | CONCURRENT_ACTIONS : (function() {
77 | var default_concurrent_actions = 1;
78 | if (semver.satisfies(process.versions.node, '>= 4.0.0'))
79 | default_concurrent_actions = 2;
80 | var concurrent_actions = parseInt(process.env.PM2_CONCURRENT_ACTIONS) || default_concurrent_actions;
81 | debug('Using %d parallelism (CONCURRENT_ACTIONS)', concurrent_actions);
82 | return concurrent_actions;
83 | })(),
84 |
85 | DEBUG : process.env.PM2_DEBUG || false,
86 | WEB_IPADDR : process.env.PM2_API_IPADDR || '0.0.0.0',
87 | WEB_PORT : parseInt(process.env.PM2_API_PORT) || 9615,
88 | WEB_STRIP_ENV_VARS : process.env.PM2_WEB_STRIP_ENV_VARS || false,
89 | MODIFY_REQUIRE : process.env.PM2_MODIFY_REQUIRE || false,
90 |
91 | WORKER_INTERVAL : process.env.PM2_WORKER_INTERVAL || 30000,
92 | KILL_TIMEOUT : process.env.PM2_KILL_TIMEOUT || 1600,
93 | PM2_PROGRAMMATIC : typeof(process.env.pm_id) !== 'undefined' || process.env.PM2_PROGRAMMATIC,
94 | PM2_LOG_DATE_FORMAT : process.env.PM2_LOG_DATE_FORMAT !== undefined ? process.env.PM2_LOG_DATE_FORMAT : 'YYYY-MM-DD HH:mm:ss'
95 |
96 | };
97 |
98 | module.exports = util._extend(csts, path_structure);
99 |
--------------------------------------------------------------------------------
/vizion/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | *
4 | * * # #
5 | * # _oo0oo_ #
6 | * # o8888888o #
7 | * # 88" . "88 #
8 | * # (| -_- |) #
9 | * # 0\ = /0 #
10 | * # ___/`---'\___ #
11 | * # .' \\| |# '. #
12 | * # / \\||| : |||# \ #
13 | * # / _||||| -:- |||||- \ #
14 | * # | | \\\ - #/ | | #
15 | * # | \_| ''\---/'' |_/ | #
16 | * # \ .-\__ '-' ___/-. / #
17 | * # ___'. .' /--.--\ `. .'___ #
18 | * # ."" '< `.___\_<|>_/___.' >' "". #
19 | * # | | : `- \`.;`\ _ /`;.`/ - ` : | | #
20 | * # \ \ `_. \_ __\ /__ _/ .-` / / #
21 | * # =====`-.____`.___ \_____/___.-`___.-'===== #
22 | * # `=---=' #
23 | * # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
24 | * # #
25 | * # 佛祖保佑 永无BUG #
26 | * # #
27 | * *
28 | * Created by jianchen on 2018/5/25.
29 | */
30 | var vizion = require('vizion');
31 |
32 | /**
33 | * Grab metadata for svn/git/hg repositories
34 | */
35 | console.log('process.cwd()',`${process.cwd()}/../`)
36 | /***
37 | * 因为我的当前执行目录没有git仓库的索引,所以指到外层去做
38 | */
39 | vizion.analyze({
40 | folder :`${process.cwd()}/../`
41 | }, function(err, meta) {
42 | if (err) throw new Error(err);
43 | console.log(meta)
44 | });
45 | //
46 | // /**
47 | // * Check if a local repository is up to date with its remote
48 | // */
49 | // vizion.isUpToDate({
50 | // folder : '/tmp/folder'
51 | // }, function(err, meta) {
52 | // if (err) throw new Error(err);
53 | //
54 | // /**
55 | // *
56 | // * meta = {
57 | // * is_up_to_date : false,
58 | // * new_revision : '6d6932dac9c82f8a29ff40c1d5300569c24aa2c8'
59 | // * current_revision : 'f0a1d45936cf7a3c969e4caba96546fd23255796'
60 | // * }
61 | // *
62 | // */
63 | // });
64 | //
65 | // /**
66 | // * Update the local repository to latest commit found on the remote for its current branch
67 | // * - on fail it rollbacks to the latest commit
68 | // */
69 | // vizion.update({
70 | // folder : '/tmp/folder'
71 | // }, function(err, meta) {
72 | // if (err) throw new Error(err);
73 | //
74 | // /**
75 | // *
76 | // * meta = {
77 | // * success : true,
78 | // * current_revision : '6d6932dac9c82f8a29ff40c1d5300569c24aa2c8'
79 | // * }
80 | // *
81 | // */
82 | // });
83 | //
84 | // /**
85 | // * Revert to a specified commit
86 | // * - Eg: this does a git reset --hard
87 | // */
88 | // vizion.revertTo({
89 | // revision : 'f0a1d45936cf7a3c969e4caba96546fd23255796',
90 | // folder : '/tmp/folder'
91 | // }, function(err, data) {
92 | // if (err) throw new Error(err);
93 | //
94 | // /**
95 | // *
96 | // * data = {
97 | // * success : true,
98 | // * }
99 | // *
100 | // */
101 | // });
102 | //
103 | // /**
104 | // * If a previous commit exists it checkouts on it
105 | // */
106 | // vizion.prev({
107 | // folder : '/tmp/folder'
108 | // }, function(err, meta) {
109 | // if (err) throw new Error(err);
110 | //
111 | // /**
112 | // *
113 | // * meta = {
114 | // * success : true,
115 | // * current_revision : '6d6932dac9c82f8a29ff40c1d5300569c24aa2c8'
116 | // * }
117 | // *
118 | // */
119 | // });
120 | //
121 | // /**
122 | // * If a more recent commit exists it chekouts on it
123 | // */
124 | // vizion.next({
125 | // folder : '/tmp/folder'
126 | // }, function(err, meta) {
127 | // if (err) throw new Error(err);
128 | //
129 | // /**
130 | // *
131 | // * meta = {
132 | // * success : false,
133 | // * current_revision : '6d6932dac9c82f8a29ff40c1d5300569c24aa2c8'
134 | // * }
135 | // *
136 | // */
137 | // });
138 |
--------------------------------------------------------------------------------
/pm2/lib/API/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "script": {
3 | "type": "string",
4 | "require": true,
5 | "alias" : "exec"
6 | },
7 | "args": {
8 | "type": [
9 | "array",
10 | "string"
11 | ]
12 | },
13 | "node_args": {
14 | "type": [
15 | "array",
16 | "string"
17 | ],
18 | "alias": ["interpreterArgs", "interpreter_args"]
19 | },
20 | "name": {
21 | "type": "string"
22 | },
23 | "max_memory_restart": {
24 | "type": [
25 | "string",
26 | "number"
27 | ],
28 | "regex": "^\\d+(G|M|K)?$",
29 | "ext_type": "sbyte",
30 | "desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)"
31 | },
32 | "uid" : {
33 | "type" : "string"
34 | },
35 | "gid" : {
36 | "type" : "string"
37 | },
38 | "restart_delay": {
39 | "type" : "number"
40 | },
41 | "source_map_support" : {
42 | "type": "boolean"
43 | },
44 | "wait_ready" : {
45 | "type": "boolean"
46 | },
47 | "disable_source_map_support" : {
48 | "type": "boolean"
49 | },
50 | "instances": {
51 | "type": "number"
52 | },
53 | "kill_timeout": {
54 | "type": "number"
55 | },
56 | "listen_timeout": {
57 | "type": "number"
58 | },
59 | "port": {
60 | "type": "number"
61 | },
62 | "log_file": {
63 | "type": [
64 | "boolean",
65 | "string"
66 | ],
67 | "alias": "log"
68 | },
69 | "error_file": {
70 | "type": "string",
71 | "alias": ["error", "err", "err_file", "err_log"]
72 | },
73 | "log_type": {
74 | "type": "string"
75 | },
76 | "out_file": {
77 | "type": "string",
78 | "alias": ["output", "out", "out_log"]
79 | },
80 | "pid_file": {
81 | "type": "string",
82 | "alias": "pid"
83 | },
84 | "cron_restart": {
85 | "type": "string",
86 | "alias": "cron"
87 | },
88 | "cwd": {
89 | "type": "string"
90 | },
91 | "merge_logs": {
92 | "type": "boolean",
93 | "alias" : "combine_logs"
94 | },
95 | "vizion" : {
96 | "type": "boolean",
97 | "default" : true
98 | },
99 | "pmx" : {
100 | "type": "boolean",
101 | "default" : true
102 | },
103 | "automation" : {
104 | "type": "boolean",
105 | "default" : true
106 | },
107 | "autorestart" : {
108 | "type": "boolean",
109 | "default" : true
110 | },
111 | "treekill" : {
112 | "type": "boolean",
113 | "default" : true
114 | },
115 | "watch": {
116 | "type": [
117 | "boolean",
118 | "array",
119 | "string"
120 | ]
121 | },
122 | "ignore_watch": {
123 | "type": [
124 | "array",
125 | "string"
126 | ]
127 | },
128 | "watch_options": {
129 | "type": "object"
130 | },
131 | "env": {
132 | "type": [
133 | "object",
134 | "string"
135 | ]
136 | },
137 | "^env_\\S*$": {
138 | "type": [
139 | "object",
140 | "string"
141 | ]
142 | },
143 | "disable_logs" : {
144 | "type": "boolean"
145 | },
146 | "log_date_format": {
147 | "type": "string"
148 | },
149 | "min_uptime": {
150 | "type": [
151 | "number",
152 | "string"
153 | ],
154 | "regex": "^\\d+(h|m|s)?$",
155 | "desc": "it should be a NUMBER - milliseconds, \"[NUMBER]h\"(hours), \"[NUMBER]m\"(minutes) or \"[NUMBER]s\"(seconds)",
156 | "min": 100,
157 | "ext_type": "stime"
158 | },
159 | "max_restarts": {
160 | "type": "number",
161 | "min": 0
162 | },
163 | "exec_mode": {
164 | "type": "string",
165 | "regex": "^(cluster|fork)(_mode)?$",
166 | "alias": "executeCommand",
167 | "desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only"
168 | },
169 | "exec_interpreter": {
170 | "type": "string",
171 | "alias": "interpreter"
172 | },
173 | "write": {
174 | "type": "boolean"
175 | },
176 | "force": {
177 | "type": "boolean"
178 | },
179 | "append_env_to_name": {
180 | "type": "boolean"
181 | },
182 | "post_update": {
183 | "type": "array"
184 | },
185 | "disable_trace": {
186 | "type": [
187 | "boolean"
188 | ]
189 | },
190 | "trace": {
191 | "type": [
192 | "boolean"
193 | ]
194 | },
195 | "v8": {
196 | "type": [
197 | "boolean"
198 | ]
199 | },
200 | "event_loop_inspector": {
201 | "type": [
202 | "boolean"
203 | ]
204 | },
205 | "deep_monitoring": {
206 | "type": [
207 | "boolean"
208 | ]
209 | },
210 | "increment_var": {
211 | "type": "string"
212 | },
213 | "instance_var": {
214 | "type": "string",
215 | "default" : "NODE_APP_INSTANCE"
216 | },
217 | "windowsHide": {
218 | "type": "boolean",
219 | "default" : true
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/pm2/lib/API/Deploy.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 |
7 | var fs = require('fs');
8 | var Deploy = require('pm2-deploy');
9 |
10 | var cst = require('../../constants.js');
11 | var Utility = require('../Utility.js');
12 | var Common = require('../Common.js');
13 |
14 | function deployHelper() {
15 | console.log('');
16 | console.log('-----> Helper: Deployment with PM2');
17 | console.log('');
18 | console.log(' Generate a sample ecosystem.config.js with the command');
19 | console.log(' $ pm2 ecosystem');
20 | console.log(' Then edit the file depending on your needs');
21 | console.log('');
22 | console.log(' Commands:');
23 | console.log(' setup run remote setup commands');
24 | console.log(' update update deploy to the latest release');
25 | console.log(' revert [n] revert to [n]th last deployment or 1');
26 | console.log(' curr[ent] output current release commit');
27 | console.log(' prev[ious] output previous release commit');
28 | console.log(' exec|run execute the given ');
29 | console.log(' list list previous deploy commits');
30 | console.log(' [ref] deploy to [ref], the "ref" setting, or latest tag');
31 | console.log('');
32 | console.log('');
33 | console.log(' Basic Examples:');
34 | console.log('');
35 | console.log(' First initialize remote production host:');
36 | console.log(' $ pm2 deploy ecosystem.config.js production setup');
37 | console.log('');
38 | console.log(' Then deploy new code:');
39 | console.log(' $ pm2 deploy ecosystem.config.js production');
40 | console.log('');
41 | console.log(' If I want to revert to the previous commit:');
42 | console.log(' $ pm2 deploy ecosystem.config.js production revert 1');
43 | console.log('');
44 | console.log(' Execute a command on remote server:');
45 | console.log(' $ pm2 deploy ecosystem.config.js production exec "pm2 restart all"');
46 | console.log('');
47 | console.log(' PM2 will look by default to the ecosystem.config.js file so you dont need to give the file name:');
48 | console.log(' $ pm2 deploy production');
49 | console.log(' Else you have to tell PM2 the name of your ecosystem file');
50 | console.log('');
51 | console.log(' More examples in https://github.com/Unitech/pm2');
52 | console.log('');
53 | };
54 |
55 | module.exports = function(CLI) {
56 | CLI.prototype.deploy = function(file, commands, cb) {
57 | var that = this;
58 |
59 | if (file == 'help') {
60 | deployHelper();
61 | return cb ? cb() : that.exitCli(cst.SUCCESS_EXIT);
62 | }
63 |
64 | var args = commands.rawArgs;
65 | var env;
66 |
67 | args.splice(0, args.indexOf('deploy') + 1);
68 |
69 | // Find ecosystem file by default
70 | if (!Common.isConfigFile(file)) {
71 | env = args[0];
72 | var defaultConfigNames = ['ecosystem.config.js', 'ecosystem.json', 'ecosystem.json5', 'package.json'];
73 | file = Utility.whichFileExists(defaultConfigNames);
74 |
75 | if (!file) {
76 | Common.printError('Not any default deployment file exists.'+
77 | ' Allowed default config file names are: ' + defaultConfigNames.join(', '));
78 | return cb ? cb('Not any default ecosystem file present') : that.exitCli(cst.ERROR_EXIT);
79 | }
80 | }
81 | else
82 | env = args[1];
83 |
84 | var json_conf = null;
85 |
86 | try {
87 | json_conf = Common.parseConfig(fs.readFileSync(file), file);
88 | } catch (e) {
89 | Common.printError(e);
90 | return cb ? cb(e) : that.exitCli(cst.ERROR_EXIT);
91 | }
92 |
93 | if (!env) {
94 | deployHelper();
95 | return cb ? cb() : that.exitCli(cst.SUCCESS_EXIT);
96 | }
97 |
98 | if (!json_conf.deploy || !json_conf.deploy[env]) {
99 | Common.printError('%s environment is not defined in %s file', env, file);
100 | return cb ? cb('%s environment is not defined in %s file') : that.exitCli(cst.ERROR_EXIT);
101 | }
102 |
103 | if (!json_conf.deploy[env]['post-deploy']) {
104 | json_conf.deploy[env]['post-deploy'] = 'pm2 startOrRestart ' + file + ' --env ' + env;
105 | }
106 |
107 | Deploy.deployForEnv(json_conf.deploy, env, args, function(err, data) {
108 | if (err) {
109 | Common.printError('Deploy failed');
110 | return cb ? cb(err) : that.exitCli(cst.ERROR_EXIT);
111 | }
112 | Common.printOut('--> Success');
113 | return cb ? cb(null, data) : that.exitCli(cst.SUCCESS_EXIT);
114 | });
115 | };
116 |
117 | };
118 |
--------------------------------------------------------------------------------
/pm2/lib/API/Keymetrics/kmapi.js:
--------------------------------------------------------------------------------
1 | var querystring = require('querystring');
2 | var https = require('https');
3 | var fs = require('fs');
4 | var needle = require('needle');
5 | var url = require('url');
6 | var cst = require('../../../constants.js');
7 |
8 | var KM = function() {
9 | this.BASE_URI = 'https://app.keymetrics.io';
10 | this.CLIENT_ID = '938758711';
11 | this.CB_URI = 'https://app.keymetrics.io';
12 | this.ACCESS_TOKEN_FILE = cst.KM_ACCESS_TOKEN;
13 | this.access_token = null;
14 | }
15 |
16 | /**
17 | * @param user_info.username
18 | * @param user_info.password
19 | * @return promise
20 | */
21 | KM.prototype.loginAndGetAccessToken = function (user_info, cb) {
22 | var that = this;
23 | var URL_AUTH = '/api/oauth/authorize?response_type=token&scope=all&client_id=' +
24 | that.CLIENT_ID + '&redirect_uri=' + that.CB_URI;
25 |
26 | needle.get(that.BASE_URI + URL_AUTH, function(err, res) {
27 | if (err) return cb(err);
28 |
29 | var cookie = res.cookies;
30 |
31 | needle.post(that.BASE_URI + '/api/oauth/login', user_info, {
32 | cookies : cookie
33 | }, function(err, resp, body) {
34 | if (err) return cb(err);
35 | if (body.indexOf('/api/oauth/login') > -1) return cb('Wrong credentials');
36 |
37 | var location = resp.headers.location;
38 | var redirect = that.BASE_URI + location;
39 |
40 | needle.get(redirect, {
41 | cookies : cookie
42 | }, function(err, res) {
43 | if (err) return cb(err);
44 | var refresh_token = querystring.parse(url.parse(res.headers.location).query).access_token;
45 |
46 | needle.post(that.BASE_URI + '/api/oauth/token', {
47 | client_id : that.CLIENT_ID,
48 | grant_type : 'refresh_token',
49 | refresh_token : refresh_token,
50 | scope : 'all'
51 | }, function(err, res, body) {
52 | if (err) return cb(err);
53 | that.access_token = body.access_token;
54 | return cb(null, body.access_token);
55 | })
56 | });
57 | });
58 | });
59 | }
60 |
61 | KM.prototype.getLocalAccessToken = function(cb) {
62 | var that = this;
63 |
64 | fs.readFile(that.ACCESS_TOKEN_FILE, function(e, content) {
65 | if (e) return cb(e);
66 | cb(null, content.toString());
67 | });
68 | };
69 |
70 | KM.prototype.saveLocalAccessToken = function(access_token, cb) {
71 | var that = this;
72 | fs.writeFile(that.ACCESS_TOKEN_FILE, access_token, function(e, content) {
73 | if (e) return cb(e);
74 | cb();
75 | });
76 | };
77 |
78 | KM.prototype.getBuckets = function(cb) {
79 | var that = this;
80 |
81 | needle.get(that.BASE_URI + '/api/bucket', {
82 | headers : {
83 | 'Authorization' : 'Bearer ' + that.access_token
84 | },
85 | json : true
86 | }, function(err, res, body) {
87 | if (err) return cb(err);
88 | return cb(null, body);
89 | });
90 | }
91 |
92 | /**
93 | * @param user_info.username
94 | * @param user_info.password
95 | * @param user_info.email
96 | * @return promise
97 | */
98 | KM.prototype.register = function(user_info, cb) {
99 | var that = this;
100 |
101 | needle.post(that.BASE_URI + '/api/oauth/register', user_info, {
102 | json: true,
103 | headers: {
104 | 'X-Register-Provider': 'pm2-register'
105 | }
106 | }, function (err, res, body) {
107 | if (err) return cb(err);
108 | if (body.email && body.email.message) return cb(body.email.message);
109 | if (body.username && body.username.message) return cb(body.username.message);
110 |
111 | cb(null, {
112 | token : body.access_token.token
113 | })
114 | });
115 | };
116 |
117 | KM.prototype.defaultNode = function(cb) {
118 | var that = this;
119 |
120 | needle.get(that.BASE_URI + '/api/node/default', function(err, res, body) {
121 | if (err) return cb(err);
122 | cb(null, url.parse(body.endpoints.web).protocol + '//' + url.parse(body.endpoints.web).hostname);
123 | });
124 | }
125 |
126 |
127 | KM.prototype.createBucket = function(default_node, bucket_name, cb) {
128 | var that = this;
129 |
130 | needle.post(default_node + '/api/bucket/create_classic', {
131 | name : bucket_name
132 | }, {
133 | json : true,
134 | headers : {
135 | 'Authorization' : 'Bearer ' + that.access_token
136 | }
137 | }, function(err, res, body) {
138 | if (err) return cb(err);
139 | cb(null, body);
140 | });
141 | }
142 |
143 | KM.prototype.fullCreationFlow = function(user_info, cb) {
144 | var that = this;
145 |
146 | this.register(user_info, function(err, dt) {
147 | if (err) return cb(err);
148 | that.access_token = dt.token;
149 | that.defaultNode(function(err, default_node) {
150 | if (err) return cb(err);
151 | that.createBucket(default_node, 'Node Monitoring', function(err, packet) {
152 | if (err) return cb(err);
153 | return cb(null, {
154 | secret_id : packet.bucket.secret_id,
155 | public_id : packet.bucket.public_id
156 | });
157 | });
158 | })
159 | });
160 | }
161 |
162 | module.exports = new KM;
163 |
--------------------------------------------------------------------------------
/pm2/lib/Worker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | var vizion = require('vizion');
7 | var cst = require('../constants.js');
8 | var async = require('async');
9 | var debug = require('debug')('pm2:worker');
10 | var domain = require('domain');
11 | var readLog = require('debug')('pm2-read');
12 | /***
13 | * worker脚本主要用来实时更新版本,内存的监控
14 | * @param God
15 | */
16 | module.exports = function(God) {
17 | var timer = null;
18 |
19 | God.Worker = {};
20 | God.Worker.is_running = false;
21 |
22 | var _getProcessById = function(pm_id) {
23 | var proc = God.clusters_db[pm_id];
24 | return proc ? proc : null;
25 | };
26 |
27 | var maxMemoryRestart = function(proc_key, cb) {
28 | var proc = _getProcessById(proc_key.pm2_env.pm_id);
29 |
30 | if (!(proc &&
31 | proc.pm2_env &&
32 | proc_key.monit))
33 | return cb();
34 |
35 | if (proc_key.monit.memory !== undefined &&
36 | proc.pm2_env.max_memory_restart !== undefined &&
37 | proc.pm2_env.max_memory_restart < proc_key.monit.memory &&
38 | proc.pm2_env.axm_options &&
39 | proc.pm2_env.axm_options.pid === undefined) {
40 | console.log('[PM2][WORKER] Process %s restarted because it exceeds --max-memory-restart value (current_memory=%s max_memory_limit=%s [octets])', proc.pm2_env.pm_id, proc_key.monit.memory, proc.pm2_env.max_memory_restart);
41 | // 如果设置了内存超过某个数值重启,则平滑重启
42 | God.softReloadProcessId({
43 | id : proc.pm2_env.pm_id
44 | }, function(err, data) {
45 | if (err)
46 | console.error(err.stack || err);
47 | return cb();
48 | });
49 | }
50 | else {
51 | return cb();
52 | }
53 | };
54 | // 版本跟新,Vizion版本更新同步
55 | var versioningRefresh = function(proc_key, cb) {
56 | var proc = _getProcessById(proc_key.pm2_env.pm_id);
57 | if (!(proc &&
58 | proc.pm2_env &&
59 | (proc.pm2_env.vizion !== false && proc.pm2_env.vizion != "false") &&
60 | proc.pm2_env.versioning &&
61 | proc.pm2_env.versioning.repo_path)) {
62 | return cb();
63 | }
64 |
65 | if (proc.pm2_env.vizion_running === true)
66 | {
67 | debug('Vizion is already running for proc id: %d, skipping this round', proc.pm2_env.pm_id);
68 | return cb();
69 | }
70 |
71 | proc.pm2_env.vizion_running = true;
72 | var repo_path = proc.pm2_env.versioning.repo_path;
73 | console.log('proc.pm2_env.versioning.repo_path',proc.pm2_env.versioning.repo_path)
74 | vizion.analyze({
75 | folder: proc.pm2_env.versioning.repo_path
76 | },
77 | function(err, meta) {
78 | if (err != null)
79 | return cb();
80 |
81 | proc = _getProcessById(proc_key.pm2_env.pm_id);
82 |
83 | if (!(proc &&
84 | proc.pm2_env &&
85 | proc.pm2_env.versioning &&
86 | proc.pm2_env.versioning.repo_path)) {
87 | console.error('Proc not defined anymore or versioning unknown');
88 | return cb();
89 | }
90 |
91 | proc.pm2_env.vizion_running = false;
92 | meta.repo_path = repo_path;
93 | proc.pm2_env.versioning = meta;
94 | debug('[PM2][WORKER] %s parsed for versioning', proc.pm2_env.name);
95 | return cb();
96 | });
97 | };
98 |
99 | // 这个任务主要检查版本和最大内存
100 | var tasks = function() {
101 | if (God.Worker.is_running === true) {
102 | debug('[PM2][WORKER] Worker is already running, skipping this round');
103 | return false;
104 | }
105 | God.Worker.is_running = true;
106 | readLog('God自身调用getMonitorData')
107 | God.getMonitorData(null, function(err, data) {
108 | if (err || !data || typeof(data) !== 'object') {
109 | God.Worker.is_running = false;
110 | return console.error(err);
111 | }
112 |
113 | async.eachLimit(data, 1, function(proc_key, next) {
114 | if (!proc_key ||
115 | !proc_key.pm2_env ||
116 | proc_key.pm2_env.pm_id === undefined)
117 | return next();
118 |
119 | debug('[PM2][WORKER] Processing proc id:', proc_key.pm2_env.pm_id);
120 |
121 | versioningRefresh(proc_key, function() {
122 | maxMemoryRestart(proc_key, function() {
123 | return next();
124 | });
125 | });
126 | }, function(err) {
127 | God.Worker.is_running = false;
128 | readLog('[PM2][WORKER] My job here is done, next job in %d seconds', parseInt(cst.WORKER_INTERVAL / 1000))
129 | debug('[PM2][WORKER] My job here is done, next job in %d seconds', parseInt(cst.WORKER_INTERVAL / 1000));
130 | });
131 | });
132 | };
133 |
134 | var wrappedTasks = function() {
135 | var d = domain.create();
136 |
137 | d.once('error', function(err) {
138 | console.error('[PM2][WORKER] Error caught by domain:\n' + (err.stack || err));
139 | God.Worker.is_running = false;
140 | });
141 |
142 | d.run(function() {
143 | tasks();
144 | });
145 | };
146 |
147 |
148 | God.Worker.start = function() {
149 | timer = setInterval(wrappedTasks, cst.WORKER_INTERVAL);
150 | };
151 |
152 | God.Worker.stop = function() {
153 | if (timer !== null)
154 | clearInterval(timer);
155 | };
156 | };
157 |
--------------------------------------------------------------------------------
/pm2/lib/API/Interaction.js:
--------------------------------------------------------------------------------
1 |
2 | var cst = require('../../constants.js');
3 | var Common = require('../Common.js');
4 | var UX = require('./CliUx');
5 | var chalk = require('chalk');
6 | var async = require('async');
7 | var path = require('path');
8 | var fs = require('fs');
9 | var KMDaemon = require('../Interactor/InteractorDaemonizer');
10 |
11 | module.exports = function(CLI) {
12 |
13 | var installServerMonit = function(CLI, cb) {
14 | if (process.env.NO_SERVER_MONIT ||
15 | process.env.NODE_ENV == 'test' ||
16 | cst.IS_WINDOWS == true)
17 | return cb();
18 |
19 | CLI.Client.executeRemote('getMonitorData', {}, function(err, list) {
20 | var installed = list.some(function(app) {
21 | return app.name == 'pm2-server-monit';
22 | });
23 | if (installed == false)
24 | CLI.install('pm2-server-monit', cb);
25 | else cb();
26 | })
27 | };
28 |
29 | /**
30 | * Launch interactor
31 | * For programmatic interaction
32 | * http://pm2.keymetrics.io/docs/usage/use-pm2-with-cloud-providers/
33 | * @method interact
34 | * @param {string} secret_key
35 | * @param {string} public_key
36 | * @param {string} machine_name
37 | */
38 | CLI.prototype.interact = function(secret_key, public_key, machine_name, cb) {
39 | var that = this;
40 |
41 | if (typeof(machine_name) == 'function') {
42 | cb = machine_name;
43 | machine_name = null;
44 | }
45 | KMDaemon.launchAndInteract(that._conf, {
46 | secret_key : secret_key || null,
47 | public_key : public_key || null,
48 | machine_name : machine_name || null
49 | }, function(err, dt) {
50 | if (err) {
51 | return cb ? cb(err) : that.exitCli(cst.ERROR_EXIT);
52 | }
53 | return cb ? cb(null, dt) : that.exitCli(cst.SUCCESS_EXIT);
54 | });
55 | };
56 |
57 | /**
58 | * Aliases
59 | */
60 | CLI.prototype.link = CLI.prototype.interact;
61 |
62 | CLI.prototype.unlink = function(cb) {
63 | this._pre_interact('delete', cb);
64 | };
65 |
66 | CLI.prototype.interactInfos = function(cb) {
67 | KMDaemon.getInteractInfo(this._conf, function(err, data) {
68 | if (err)
69 | return cb(Common.retErr(err));
70 | return cb(null, data);
71 | });
72 | };
73 |
74 | //
75 | // Interact
76 | //
77 | CLI.prototype._pre_interact = function(cmd, public_key, machine, info_node) {
78 | var that = this;
79 |
80 | if (cmd == 'stop' || cmd == 'kill') {
81 | console.log(chalk.cyan('[Keymetrics.io]') + ' Stopping agent...');
82 | that.killInteract(function() {
83 | console.log(chalk.cyan('[Keymetrics.io]') + ' Stopped');
84 | return process.exit(cst.SUCCESS_EXIT);
85 | });
86 | return false;
87 | }
88 |
89 | if (cmd == 'info') {
90 | console.log(chalk.cyan('[Keymetrics.io]') + ' Getting agent information...');
91 | that.interactInfos(function(err, infos) {
92 | if (err) {
93 | console.error(err.message);
94 | return that.exitCli(cst.ERROR_EXIT);
95 | }
96 | console.log(infos);
97 | return that.exitCli(cst.SUCCESS_EXIT);
98 | });
99 | return false;
100 | }
101 |
102 | if (cmd == 'delete') {
103 | that.killInteract(function() {
104 | try {
105 | fs.unlinkSync(cst.INTERACTION_CONF);
106 | } catch(e) {
107 | console.log(chalk.cyan('[Keymetrics.io]') + ' No interaction config file found');
108 | return process.exit(cst.SUCCESS_EXIT);
109 | }
110 | console.log(chalk.cyan('[Keymetrics.io]') + ' Agent interaction ended');
111 | return process.exit(cst.SUCCESS_EXIT);
112 | });
113 | return false;
114 | }
115 |
116 | if (cmd == 'start' || cmd == 'restart') {
117 | KMDaemon.launchAndInteract(that._conf, {
118 | public_key : null,
119 | secret_key : null,
120 | machine_name : null,
121 | info_node : null
122 | }, function(err, dt) {
123 | if (err) {
124 | Common.printError(err);
125 | return that.exitCli(cst.ERROR_EXIT);
126 | }
127 | return that.exitCli(cst.SUCCESS_EXIT);
128 | });
129 | }
130 |
131 | if (cmd && !public_key) {
132 | console.error(chalk.cyan('[Keymetrics.io]') + ' Command [%s] unknown or missing public key', cmd);
133 | return process.exit(cst.ERROR_EXIT);
134 | }
135 |
136 | var infos;
137 |
138 | if (!cmd) {
139 | infos = null;
140 | }
141 | else
142 | infos = {
143 | public_key : public_key,
144 | secret_key : cmd,
145 | machine_name : machine,
146 | info_node : info_node.infoNode || null
147 | }
148 |
149 | KMDaemon.launchAndInteract(that._conf, infos, function(err, dt) {
150 | if (err)
151 | return that.exitCli(cst.ERROR_EXIT);
152 | return that.exitCli(cst.SUCCESS_EXIT);
153 | });
154 | };
155 |
156 | /**
157 | * Kill interactor
158 | * @method killInteract
159 | */
160 | CLI.prototype.killInteract = function(cb) {
161 | var that = this;
162 | KMDaemon.killInteractorDaemon(that._conf, function(err) {
163 | return cb ? cb(Common.retErr('Interactor not launched')) : that.exitCli(cst.SUCCESS_EXIT);
164 | });
165 | };
166 |
167 | };
168 |
--------------------------------------------------------------------------------
/pm2/lib/API/Modules/Modularizerv1.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | var shelljs = require('shelljs');
7 | var path = require('path');
8 | var fs = require('fs');
9 | var async = require('async');
10 | var p = path;
11 | var spawn = require('child_process').spawn;
12 | var chalk = require('chalk');
13 | var Configuration = require('../../Configuration.js');
14 | var cst = require('../../../constants.js');
15 | var Common = require('../../Common');
16 | var Utility = require('../../Utility.js');
17 |
18 | var MODULE_CONF_PREFIX = 'module-db';
19 |
20 | var Modularizer = module.exports = {};
21 |
22 | function startModule(CLI, opts, cb) {
23 | /** SCRIPT
24 | * Open file and make the script detection smart
25 | */
26 |
27 | if (!opts.cmd) throw new Error('module package.json not defined');
28 | if (!opts.development_mode) opts.development_mode = false;
29 |
30 | try {
31 | var package_json = require(opts.cmd);
32 | } catch(e) {
33 | Common.printError(e);
34 | return cb();
35 | }
36 |
37 | /**
38 | * Script file detection
39 | * 1- *apps* field (default pm2 json configuration)
40 | * 2- *bin* field
41 | * 3- *main* field
42 | */
43 | if (!package_json.apps) {
44 | package_json.apps = {};
45 |
46 | if (package_json.bin) {
47 | var bin = Object.keys(package_json.bin)[0];
48 |
49 | package_json.apps.script = package_json.bin[bin];
50 | }
51 | else if (package_json.main) {
52 | package_json.apps.script = package_json.main;
53 | }
54 | }
55 |
56 | Common.extend(opts, {
57 | cwd : opts.proc_path,
58 | watch : opts.development_mode,
59 | force_name : package_json.name,
60 | started_as_module : true
61 | });
62 |
63 | // Start the module
64 | CLI.start(package_json, opts, function(err, data) {
65 | if (err) return cb(err);
66 | return cb(null, data);
67 | });
68 | };
69 |
70 | Modularizer.launchModules = function(CLI, cb) {
71 | var module_folder = p.join(cst.PM2_ROOT_PATH, 'node_modules');
72 | var modules = Configuration.getSync(MODULE_CONF_PREFIX);
73 |
74 | if (!modules) return cb();
75 |
76 | async.eachLimit(Object.keys(modules), 1, function(module, next) {
77 | var pmod = p.join(module_folder, module, cst.DEFAULT_MODULE_JSON);
78 |
79 | Common.printOut(cst.PREFIX_MSG_MOD + 'Starting module ' + module);
80 |
81 | var opts = {};
82 |
83 | if (modules[module] != true) {
84 | Common.extend(opts, modules[module]);
85 | }
86 |
87 | Common.extend(opts, {
88 | cmd : pmod,
89 | development_mode : false,
90 | proc_path : p.join(module_folder, module)
91 | });
92 |
93 | startModule(CLI, opts, function(err, dt) {
94 | if (err) console.error(err);
95 | return next();
96 | });
97 |
98 | }, function() {
99 | return cb ? cb(null) : false;
100 | });
101 | }
102 |
103 | Modularizer.installModule = function(CLI, module_name, opts, cb) {
104 | var proc_path = '',
105 | cmd = '',
106 | conf = {},
107 | development_mode = false;
108 |
109 | var cli = {
110 | bin : 'npm',
111 | cmd : 'install'
112 | }
113 |
114 | Common.printOut(cst.PREFIX_MSG_MOD + 'Calling ' + chalk.bold.red('[' + cli.bin.toUpperCase() + ']') + ' to install ' + module_name + ' ...');
115 |
116 | var install_instance = spawn(cst.IS_WINDOWS ? cli.bin + '.cmd' : cli.bin, [cli.cmd, module_name, '--loglevel=error'], {
117 | stdio : 'inherit',
118 | env: process.env,
119 | shell : true,
120 | cwd : cst.PM2_ROOT_PATH
121 | });
122 |
123 | install_instance.on('close', finalize);
124 |
125 | install_instance.on('error', function (err) {
126 | console.error(err.stack || err);
127 | });
128 |
129 | function finalize(code) {
130 | if (code != 0) {
131 | return cb(new Error("Installation failed"));
132 | }
133 |
134 | Common.printOut(cst.PREFIX_MSG_MOD + 'Module downloaded');
135 |
136 | var canonic_module_name = Utility.getCanonicModuleName(module_name);
137 |
138 | proc_path = p.join(cst.PM2_ROOT_PATH, 'node_modules', canonic_module_name);
139 |
140 | cmd = p.join(proc_path, cst.DEFAULT_MODULE_JSON);
141 |
142 | /**
143 | * Append default configuration to module configuration
144 | */
145 | try {
146 | var conf = JSON.parse(fs.readFileSync(path.join(proc_path, 'package.json')).toString()).config;
147 | if (conf) {
148 | Object.keys(conf).forEach(function(key) {
149 | Configuration.setSyncIfNotExist(canonic_module_name + ':' + key, conf[key]);
150 | });
151 | }
152 | } catch(e) {
153 | Common.printError(e);
154 | }
155 |
156 | opts = Common.extend(opts, {
157 | cmd : cmd,
158 | development_mode : development_mode,
159 | proc_path : proc_path
160 | });
161 |
162 | Configuration.set(MODULE_CONF_PREFIX + ':' + canonic_module_name, {
163 | uid : opts.uid,
164 | gid : opts.gid,
165 | version : 0
166 | }, function(err, data) {
167 |
168 | startModule(CLI, opts, function(err, dt) {
169 | if (err) return cb(err);
170 |
171 | if (process.env.PM2_PROGRAMMATIC === 'true')
172 | return cb(null, dt);
173 |
174 | CLI.conf(canonic_module_name, function() {
175 | Common.printOut(cst.PREFIX_MSG_MOD + 'Module successfully installed and launched');
176 | Common.printOut(cst.PREFIX_MSG_MOD + 'Edit configuration via: `pm2 conf`');
177 | return cb(null, dt);
178 | });
179 | });
180 | });
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/pm2/lib/binaries/DevCLI.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | process.env.PM2_NO_INTERACTION = 'true';
5 | // Do not print banner
6 | process.env.PM2_DISCRETE_MODE = true;
7 |
8 | var commander = require('commander');
9 |
10 | var debug = require('debug')('pm2:cli');
11 | var PM2 = require('../..');
12 | var Log = require('../API/Log');
13 | var cst = require('../../constants.js');
14 | var pkg = require('../../package.json');
15 | var platform = require('os').platform();
16 | var moment = require('moment');
17 | var Common = require('../Common');
18 | var chalk = require('chalk');
19 | var path = require('path');
20 | var fmt = require('../tools/fmt.js');
21 | var exec = require('child_process').exec;
22 | var os = require('os');
23 |
24 | commander.version(pkg.version)
25 | .description('pm2-dev monitor for any file changes and automatically restart it')
26 | .option('--raw', 'raw log output')
27 | .option('--timestamp', 'print timestamp')
28 | .option('--node-args ', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"')
29 | .option('--ignore [files]', 'files to ignore while watching')
30 | .option('--post-exec [cmd]', 'execute extra command after change detected')
31 | .option('--silent-exec', 'do not output result of post command', false)
32 | .option('--test-mode', 'debug mode for test suit')
33 | .option('--interpreter ', 'the interpreter pm2 should use for executing app (bash, python...)')
34 | .option('--env [name]', 'select env_[name] env variables in process config file')
35 | .option('--auto-exit', 'exit if all processes are errored/stopped or 0 apps launched')
36 | .usage('pm2-dev app.js');
37 |
38 | var pm2 = new PM2.custom({
39 | pm2_home : path.join(os.homedir ? os.homedir() : (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE), '.pm2-dev')
40 | });
41 |
42 | pm2.connect(function() {
43 | commander.parse(process.argv);
44 | });
45 |
46 | function postExecCmd(command, cb) {
47 | var exec_cmd = exec(command);
48 |
49 | if (commander.silentExec !== true) {
50 | exec_cmd.stdout.on('data', function(data) {
51 | process.stdout.write(data);
52 | });
53 |
54 | exec_cmd.stderr.on('data', function(data) {
55 | process.stderr.write(data);
56 | });
57 | }
58 |
59 | exec_cmd.on('close', function done() {
60 | if (cb) cb(null);
61 | });
62 |
63 | exec_cmd.on('error', function (err) {
64 | console.error(err.stack || err);
65 | });
66 | };
67 |
68 | function run(cmd, opts) {
69 | var timestamp = opts.timestamp;
70 |
71 | opts.watch = true;
72 | opts.autorestart = true;
73 |
74 | if (opts.autoExit)
75 | autoExit();
76 |
77 | if (opts.ignore) {
78 | opts.ignore_watch = opts.ignore.split(',')
79 | opts.ignore_watch.push('node_modules');
80 | }
81 |
82 | if (timestamp === true)
83 | timestamp = 'YYYY-MM-DD-HH:mm:ss';
84 |
85 | pm2.start(cmd, opts, function(err, procs) {
86 |
87 | if (err) {
88 | console.error(err);
89 | pm2.destroy(function() {
90 | process.exit(0);
91 | });
92 | return false;
93 | }
94 |
95 | if (opts.testMode) {
96 | return pm2.disconnect(function() {
97 | });
98 | }
99 |
100 | fmt.sep();
101 | fmt.title('PM2 development mode');
102 | fmt.field('Apps started', procs.map(function(p) { return p.pm2_env.name } ));
103 | fmt.field('Processes started', chalk.bold(procs.length));
104 | fmt.field('Watch and Restart', chalk.green('Enabled'));
105 | fmt.field('Ignored folder', opts.ignore_watch || 'node_modules');
106 | if (opts.postExec)
107 | fmt.field('Post restart cmd', opts.postExec);
108 | fmt.sep();
109 |
110 | setTimeout(function() {
111 | pm2.Client.launchBus(function(err, bus) {
112 | bus.on('process:event', function(packet) {
113 | if (packet.event == 'online') {
114 | if (opts.postExec)
115 | postExecCmd(opts.postExec);
116 | }
117 | });
118 | });
119 | }, 1000);
120 |
121 | Log.devStream(pm2.Client, 'all', opts.raw, timestamp, false);
122 |
123 | process.on('SIGINT', function() {
124 | console.log('>>>>> [PM2 DEV] Stopping current development session');
125 | pm2.delete('all', function() {
126 | pm2.destroy(function() {
127 | process.exit(0);
128 | });
129 | });
130 | });
131 |
132 | });
133 | }
134 |
135 | commander.command('*')
136 | .action(function(cmd, opts){
137 | run(cmd, commander);
138 | });
139 |
140 | commander.command('start ')
141 | .description('start target config file/script in development mode')
142 | .action(function(cmd, opts) {
143 | run(cmd, commander);
144 | });
145 |
146 | function exitPM2() {
147 | if (pm2 && pm2.connected == true) {
148 | console.log(chalk.green.bold('>>> Exiting PM2'));
149 | pm2.kill(function() {
150 | process.exit(0);
151 | });
152 | }
153 | else
154 | process.exit(0);
155 | }
156 |
157 | function autoExit(final) {
158 | setTimeout(function() {
159 | pm2.list(function(err, apps) {
160 | if (err) console.error(err.stack || err);
161 |
162 | var online_count = 0;
163 |
164 | apps.forEach(function(app) {
165 | if (app.pm2_env.status == cst.ONLINE_STATUS ||
166 | app.pm2_env.status == cst.LAUNCHING_STATUS)
167 | online_count++;
168 | });
169 |
170 | if (online_count == 0) {
171 | console.log('0 application online, exiting');
172 | if (final == true)
173 | process.exit(1);
174 | else
175 | autoExit(true);
176 | return false;
177 | }
178 | autoExit(false);
179 | });
180 | }, 3000);
181 | }
182 |
183 | if (process.argv.length == 2) {
184 | commander.outputHelp();
185 | exitPM2();
186 | }
187 |
--------------------------------------------------------------------------------
/pm2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "pm2",
3 | "_id": "pm2@2.10.3",
4 | "_inBundle": false,
5 | "_integrity": "sha1-DzODSgmgYQ22WjoOEKKBwSNWdzI=",
6 | "_location": "/pm2",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "tag",
10 | "registry": true,
11 | "raw": "pm2",
12 | "name": "pm2",
13 | "escapedName": "pm2",
14 | "rawSpec": "",
15 | "saveSpec": null,
16 | "fetchSpec": "latest"
17 | },
18 | "_requiredBy": [
19 | "#USER",
20 | "/"
21 | ],
22 | "_resolved": "http://r.npm.sankuai.com/pm2/download/pm2-2.10.3.tgz",
23 | "_shasum": "0f33834a09a0610db65a3a0e10a281c123567732",
24 | "_spec": "pm2",
25 | "_where": "/Users/jianchen/WebstormProjects/nodeprocess",
26 | "author": {
27 | "name": "Strzelewicz Alexandre",
28 | "email": "alexandre@keymetrics.io",
29 | "url": "https://keymetrics.io"
30 | },
31 | "bin": {
32 | "pm2": "./bin/pm2",
33 | "pm2-dev": "./bin/pm2-dev",
34 | "pm2-docker": "./bin/pm2-docker",
35 | "pm2-runtime": "./bin/pm2-runtime"
36 | },
37 | "bugs": {
38 | "url": "https://github.com/Unitech/pm2/issues"
39 | },
40 | "bundleDependencies": false,
41 | "contributors": [
42 | {
43 | "name": "Alex Kocharin",
44 | "email": "alex@kocharin.ru"
45 | },
46 | {
47 | "name": "Soyuka",
48 | "email": "soyuka@gmail.com"
49 | },
50 | {
51 | "name": "Joni Shkurti",
52 | "email": "jonishkurti90@gmail.com"
53 | },
54 | {
55 | "name": "James Ide"
56 | },
57 | {
58 | "name": "Jun Tjatse",
59 | "email": "thisnamemeansnothing@gmail.com"
60 | },
61 | {
62 | "name": "Xu Jingxin",
63 | "email": "sailxjx@gmail.com"
64 | },
65 | {
66 | "name": "Ben Postlethwaite",
67 | "email": "post.ben.here@gmail.com"
68 | },
69 | {
70 | "name": "Devo.ps",
71 | "email": "contact@devo.ps"
72 | },
73 | {
74 | "name": "Bret Copeland",
75 | "email": "bret@atlantisflight.org"
76 | },
77 | {
78 | "name": "John Hurliman",
79 | "email": "jhurliman@jhurliman.org"
80 | },
81 | {
82 | "name": "TruongSinh Tran-Nguyen",
83 | "email": "i@truongsinh.pro"
84 | },
85 | {
86 | "name": "Michael Hueuberger",
87 | "email": "michael.heuberger@binarykitchen.com"
88 | },
89 | {
90 | "name": "Chris Wiggins",
91 | "email": "chris@chriswiggins.co.nz"
92 | }
93 | ],
94 | "dependencies": {
95 | "async": "^2.5",
96 | "blessed": "^0.1.81",
97 | "chalk": "^1.1",
98 | "chokidar": "^2",
99 | "cli-table-redemption": "^1.0.0",
100 | "commander": "2.13.0",
101 | "cron": "^1.3",
102 | "debug": "^3.0",
103 | "eventemitter2": "1.0.5",
104 | "fclone": "1.0.11",
105 | "gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz",
106 | "mkdirp": "0.5.1",
107 | "moment": "^2.19",
108 | "needle": "^2.1.0",
109 | "nssocket": "0.6.0",
110 | "pidusage": "^1.2.0",
111 | "pm2-axon": "3.1.0",
112 | "pm2-axon-rpc": "^0.5.1",
113 | "pm2-deploy": "^0.3.9",
114 | "pm2-multimeter": "^0.1.2",
115 | "pmx": "^1.6",
116 | "promptly": "2.2.0",
117 | "semver": "^5.3",
118 | "shelljs": "0.7.8",
119 | "source-map-support": "^0.5",
120 | "sprintf-js": "1.1.1",
121 | "v8-compile-cache": "^1.1.0",
122 | "vizion": "^0.2",
123 | "yamljs": "^0.3.0"
124 | },
125 | "deprecated": false,
126 | "description": "Production process manager for Node.JS applications with a built-in load balancer.",
127 | "devDependencies": {
128 | "mocha": "^3.5",
129 | "should": "^11"
130 | },
131 | "directories": {
132 | "bin": "./bin",
133 | "lib": "./lib",
134 | "example": "./examples"
135 | },
136 | "engines": {
137 | "node": ">=0.12"
138 | },
139 | "homepage": "http://pm2.keymetrics.io/",
140 | "keywords": [
141 | "cli",
142 | "fault tolerant",
143 | "sysadmin",
144 | "tools",
145 | "pm2",
146 | "logs",
147 | "log",
148 | "json",
149 | "express",
150 | "hapi",
151 | "kraken",
152 | "reload",
153 | "load balancer",
154 | "lb",
155 | "load-balancer",
156 | "kubernetes",
157 | "k8s",
158 | "pm2-docker",
159 | "runtime",
160 | "source maps",
161 | "graceful",
162 | "microservice",
163 | "programmatic",
164 | "harmony",
165 | "node-pm2",
166 | "production",
167 | "keymetrics",
168 | "node.js monitoring",
169 | "strong-pm",
170 | "deploy",
171 | "deployment",
172 | "daemon",
173 | "supervisor",
174 | "supervisord",
175 | "nodemon",
176 | "pm2.io",
177 | "ghost",
178 | "ghost production",
179 | "monitoring",
180 | "keymetrics",
181 | "process manager",
182 | "forever",
183 | "profiling",
184 | "probes",
185 | "apm",
186 | "container",
187 | "forever-monitor",
188 | "keep process alive",
189 | "process configuration",
190 | "clustering",
191 | "cluster cli",
192 | "cluster",
193 | "docker",
194 | "cron",
195 | "devops",
196 | "dev ops"
197 | ],
198 | "license": "AGPL-3.0",
199 | "main": "index.js",
200 | "maintainers": [
201 | {
202 | "name": "tknew",
203 | "email": "strzelewicz.alexandre@gmail.com"
204 | },
205 | {
206 | "name": "soyuka",
207 | "email": "soyuka@gmail.com"
208 | },
209 | {
210 | "name": "wallet77",
211 | "email": "wallet77@gmail.com"
212 | },
213 | {
214 | "name": "vmarchaud",
215 | "email": "contact@vmarchaud.fr"
216 | }
217 | ],
218 | "name": "pm2",
219 | "optionalDependencies": {
220 | "gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz"
221 | },
222 | "preferGlobal": true,
223 | "repository": {
224 | "type": "git",
225 | "url": "git://github.com/Unitech/pm2.git"
226 | },
227 | "scripts": {
228 | "bench-pmx": "pm2 delete all; pm2 install pm2-probe; node examples/pmx/app.js; pm2 ls",
229 | "test": "NODE_ENV=test bash test/pm2_check_dependencies.sh && NODE_ENV=test bash test/pm2_programmatic_tests.sh && NODE_ENV=test bash test/pm2_behavior_tests.sh"
230 | },
231 | "types": "types/index.d.ts",
232 | "version": "2.10.3"
233 | }
234 |
--------------------------------------------------------------------------------
/pm2/lib/API/Modules/Modules.js:
--------------------------------------------------------------------------------
1 |
2 | /***************************
3 | *
4 | * Module methods
5 | *
6 | **************************/
7 |
8 | var cst = require('../../../constants.js');
9 | var Common = require('../../Common.js');
10 | var UX = require('../CliUx');
11 | var chalk = require('chalk');
12 | var async = require('async');
13 |
14 | var shelljs = require('shelljs');
15 | var path = require('path');
16 | var fs = require('fs');
17 | var p = path;
18 | var Configuration = require('../../Configuration.js');
19 | var Utility = require('../../Utility.js');
20 |
21 | var MODULE_CONF_PREFIX = 'module-db';
22 |
23 | var Modularizer = require('./Modularizer.js');
24 | var ModularizerV1 = require('./Modularizerv1.js');
25 |
26 | // Special module with post display
27 | function postDisplay(app, cb) {
28 | var that = this;
29 | var retry = 0;
30 |
31 | UX.processing.start('Initializing module');
32 |
33 | (function detectModuleInit() {
34 | retry++;
35 | if (retry > 12) {
36 | // Module init has timeouted
37 | return displayOrNot(null);
38 | }
39 | that.describe(app.pm_id, function(err, data) {
40 |
41 | if (data && data[0] && data[0].pm2_env &&
42 | data[0].pm2_env.axm_options &&
43 | data[0].pm2_env.axm_options.human_info) {
44 | return displayOrNot(data[0]);
45 | }
46 | setTimeout(function() {
47 | detectModuleInit();
48 | }, 300);
49 | });
50 | })();
51 |
52 | function displayOrNot(app) {
53 | UX.processing.stop();
54 |
55 | if (app) {
56 | var module_name = app.name;
57 | var human_info = app.pm2_env.axm_options.human_info;
58 |
59 | UX.postModuleInfos(module_name, human_info);
60 | Common.printOut(chalk.white.italic(' Use `pm2 show %s` to display this helper'), module_name);
61 | Common.printOut(chalk.white.italic(' Use `pm2 logs %s [--lines 1000]` to display logs'), module_name);
62 | Common.printOut(chalk.white.italic(' Use `pm2 monit` to monitor CPU and Memory usage'), module_name);
63 | return cb ? cb(null, app) : that.exitCli(cst.SUCCESS_EXIT);
64 | }
65 |
66 | return cb ? cb(null, { msg : 'Module started' }) : that.speedList(cst.SUCCESS_EXIT);
67 | }
68 | }
69 |
70 | module.exports = function(CLI) {
71 | /**
72 | * Install / Update a module
73 | */
74 | CLI.prototype.install = function(module_name, opts, cb) {
75 | var that = this;
76 |
77 | if (typeof(opts) == 'function') {
78 | cb = opts;
79 | opts = {};
80 | }
81 |
82 | // Because for test, allow to install module in V1 way
83 | if (opts.v1) {
84 | Common.printOut('Installing the V1 way...');
85 | console.log(opts.uid, opts.gid, opts.v1);
86 | ModularizerV1.installModule(this, module_name, opts, function(err, data) {
87 | if (err) {
88 | Common.printError(cst.PREFIX_MSG_ERR + (err.message || err));
89 | return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
90 | }
91 |
92 | // Check if special module with post_install display
93 | if (data && data[0] && data[0].pm2_env && data[0].pm2_env.PM2_EXTRA_DISPLAY) {
94 | return postDisplay.call(that, data[0].pm2_env, cb);
95 | }
96 | return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
97 | });
98 | return false;
99 | }
100 |
101 | Modularizer.install(this, module_name, opts, function(err, data) {
102 | if (err) {
103 | Common.printError(cst.PREFIX_MSG_ERR + (err.message || err));
104 | return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
105 | }
106 |
107 | // Check if special module with post_install display
108 | if (data && data[0] && data[0].pm2_env && data[0].pm2_env.PM2_EXTRA_DISPLAY) {
109 | return postDisplay.call(that, data[0].pm2_env, cb);
110 | }
111 | return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
112 | });
113 | };
114 |
115 | /**
116 | * Uninstall a module
117 | */
118 | CLI.prototype.uninstall = function(module_name, cb) {
119 | var that = this;
120 |
121 | Modularizer.uninstall(this, module_name, function(err, data) {
122 | if (err)
123 | return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
124 | return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
125 | });
126 | };
127 |
128 | /**
129 | * Publish module on NPM + Git push
130 | */
131 | CLI.prototype.publish = function(module_name, cb) {
132 | var that = this;
133 |
134 | Modularizer.publish(function(err, data) {
135 | if (err)
136 | return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
137 | return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
138 | });
139 | };
140 |
141 | /**
142 | * Publish module on NPM + Git push
143 | */
144 | CLI.prototype.generateModuleSample = function(app_name, cb) {
145 | var that = this;
146 |
147 | Modularizer.generateSample(app_name, function(err, data) {
148 | if (err)
149 | return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
150 | return cb ? cb(null, data) : that.exitCli(cst.SUCCESS_EXIT);
151 | });
152 | };
153 |
154 | CLI.prototype.killAllModules = function(cb) {
155 | var that = this;
156 |
157 | this.Client.getAllModulesId(function(err, modules_id) {
158 | async.forEachLimit(modules_id, 1, function(id, next) {
159 | that._operate('deleteProcessId', id, next);
160 | }, function() {
161 | return cb ? cb() : false;
162 | });
163 | });
164 | };
165 |
166 | CLI.prototype.deleteModule = function(module_name, cb) {
167 | var that = this;
168 |
169 | var found_proc = [];
170 |
171 | this.Client.getAllProcess(function(err, procs) {
172 | if (err) {
173 | Common.printError('Error retrieving process list: ' + err);
174 | return cb(Common.retErr(err));
175 | }
176 |
177 | procs.forEach(function(proc) {
178 | if (proc.pm2_env.name == module_name && proc.pm2_env.pmx_module) {
179 | found_proc.push(proc.pm_id);
180 | }
181 | });
182 |
183 | if (found_proc.length == 0)
184 | return cb();
185 |
186 | that._operate('deleteProcessId', found_proc[0], function(err) {
187 | if (err) return cb(Common.retErr(err));
188 | Common.printOut('In memory process deleted');
189 | return cb();
190 | });
191 | });
192 | };
193 | };
194 |
--------------------------------------------------------------------------------
/pm2/lib/API/Monit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | // pm2-htop
7 | // Library who interacts with PM2 to display processes resources in htop way
8 | // by Strzelewicz Alexandre
9 |
10 | var multimeter = require('pm2-multimeter');
11 | var os = require('os');
12 | var p = require('path');
13 | var chalk = require('chalk');
14 |
15 | var CliUx = require('./CliUx');
16 |
17 | var debug = require('debug')('pm2:monit');
18 |
19 | // Cst for light programs
20 | const RATIO_T1 = Math.floor(os.totalmem() / 500);
21 | // Cst for medium programs
22 | const RATIO_T2 = Math.floor(os.totalmem() / 50);
23 | // Cst for heavy programs
24 | const RATIO_T3 = Math.floor(os.totalmem() / 5);
25 | // Cst for heavy programs
26 | const RATIO_T4 = Math.floor(os.totalmem());
27 |
28 | var Monit = {};
29 |
30 | //helper to get bars.length (num bars printed)
31 | Object.size = function(obj) {
32 | var size = 0, key;
33 | for (key in obj) {
34 | if (obj.hasOwnProperty(key)) size++;
35 | }
36 | return size;
37 | };
38 |
39 | /**
40 | * Reset the monitor through charm, basically \033c
41 | * @param String msg optional message to show
42 | * @return Monit
43 | */
44 | Monit.reset = function(msg) {
45 |
46 | this.multi.charm.reset();
47 |
48 | this.multi.write('\x1B[32m⌬ PM2 \x1B[39mmonitoring\x1B[96m (To go further check out https://app.keymetrics.io) \x1B[39m\n\n');
49 |
50 | if(msg) {
51 | this.multi.write(msg);
52 | }
53 |
54 | this.bars = {};
55 |
56 | return this;
57 | }
58 |
59 | /**
60 | * Synchronous Monitor init method
61 | * @method init
62 | * @return Monit
63 | */
64 | Monit.init = function() {
65 |
66 | this.multi = multimeter(process);
67 |
68 | this.multi.on('^C', this.stop);
69 |
70 | this.reset();
71 |
72 | return this;
73 | }
74 |
75 | /**
76 | * Stops monitor
77 | * @method stop
78 | */
79 | Monit.stop = function() {
80 | this.multi.charm.destroy();
81 | process.exit(0);
82 | }
83 |
84 |
85 | /**
86 | * Refresh monitor
87 | * @method refresh
88 | * @param {} processes
89 | * @return this
90 | */
91 | Monit.refresh = function(processes) {
92 | debug('Monit refresh');
93 |
94 | if(!processes) {
95 | processes = [];
96 | }
97 |
98 | var num = processes.length;
99 | this.num_bars = Object.size(this.bars);
100 |
101 | if(num !== this.num_bars) {
102 | debug('Monit addProcesses - actual: %s, new: %s', this.num_bars, num);
103 | return this.addProcesses(processes);
104 | } else {
105 |
106 | if(num === 0) {
107 | return;
108 | }
109 |
110 | debug('Monit refresh');
111 | var proc;
112 |
113 | for(var i = 0; i < num; i++) {
114 | proc = processes[i];
115 |
116 | //this is to avoid a print issue when the process is restarted for example
117 | //we might also check for the pid but restarted|restarting will be rendered bad
118 | if(this.bars[proc.pm_id] && proc.pm2_env.status !== this.bars[proc.pm_id].status) {
119 | debug('bars for %s does not exists', proc.pm_id);
120 | this.addProcesses(processes);
121 | break;
122 | }
123 |
124 | this.updateBars(proc);
125 |
126 | }
127 | }
128 |
129 | return this;
130 | }
131 |
132 | Monit.addProcess = function(proc, i) {
133 | if(proc.pm_id in this.bars) {
134 | return ;
135 | }
136 |
137 | if (proc.monit.error)
138 | throw new Error(JSON.stringify(proc.monit.error));
139 |
140 | var process_name = proc.pm2_env.name || p.basename(proc.pm2_env.pm_exec_path);
141 | var status = proc.pm2_env.status == 'online' ? chalk.green.bold('●') : chalk.red.bold('●');
142 |
143 | this.multi.write(' ' + status + ' ' + chalk.green.bold(process_name));
144 | this.multi.write('\n');
145 | this.multi.write('[' + proc.pm2_env.pm_id + '] [' + proc.pm2_env.exec_mode + ']\n');
146 |
147 | var bar_cpu = this.multi(40, (i * 2) + 3 + i, {
148 | width: 30,
149 | solid: {
150 | text: '|',
151 | foreground: 'white',
152 | background: 'blue'
153 | },
154 | empty: {
155 | text: ' '
156 | }
157 | });
158 |
159 | var bar_memory = this.multi(40, (i * 2) + 4 + i, {
160 | width: 30,
161 | solid: {
162 | text: '|',
163 | foreground: 'white',
164 | background: 'red'
165 | },
166 | empty: {
167 | text: ' '
168 | }
169 | });
170 |
171 | this.bars[proc.pm_id] = {
172 | memory: bar_memory,
173 | cpu: bar_cpu,
174 | status: proc.pm2_env.status
175 | };
176 |
177 | this.updateBars(proc);
178 |
179 | this.multi.write('\n');
180 |
181 | return this;
182 | }
183 |
184 | Monit.addProcesses = function(processes) {
185 |
186 | if(!processes) {
187 | processes = [];
188 | }
189 |
190 | this.reset();
191 |
192 | var num = processes.length;
193 |
194 | if(num > 0) {
195 | for(var i = 0; i < num; i++) {
196 | this.addProcess(processes[i], i);
197 | }
198 | } else {
199 | this.reset('No processes to monit');
200 | }
201 |
202 | }
203 |
204 | // Draw memory bars
205 | /**
206 | * Description
207 | * @method drawRatio
208 | * @param {} bar_memory
209 | * @param {} memory
210 | * @return
211 | */
212 | Monit.drawRatio = function(bar_memory, memory) {
213 | var scale = 0;
214 |
215 | if (memory < RATIO_T1) scale = RATIO_T1;
216 | else if (memory < RATIO_T2) scale = RATIO_T2;
217 | else if (memory < RATIO_T3) scale = RATIO_T3;
218 | else scale = RATIO_T4;
219 |
220 | bar_memory.ratio(memory,
221 | scale,
222 | CliUx.bytesToSize(memory, 3));
223 | };
224 |
225 | /**
226 | * Updates bars informations
227 | * @param {} proc proc object
228 | * @return this
229 | */
230 | Monit.updateBars = function(proc) {
231 | if (this.bars[proc.pm_id]) {
232 | if (proc.pm2_env.status !== 'online' || proc.pm2_env.status !== this.bars[proc.pm_id].status) {
233 | this.bars[proc.pm_id].cpu.percent(0, chalk.red(proc.pm2_env.status));
234 | this.drawRatio(this.bars[proc.pm_id].memory, 0, chalk.red(proc.pm2_env.status));
235 | } else if (!proc.monit) {
236 | this.bars[proc.pm_id].cpu.percent(0, chalk.red('No data'));
237 | this.drawRatio(this.bars[proc.pm_id].memory, 0, chalk.red('No data'));
238 | } else {
239 | this.bars[proc.pm_id].cpu.percent(proc.monit.cpu);
240 | this.drawRatio(this.bars[proc.pm_id].memory, proc.monit.memory);
241 | }
242 | }
243 |
244 | return this;
245 | }
246 |
247 | module.exports = Monit;
--------------------------------------------------------------------------------
/pm2/lib/God/Reload.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 the PM2 project authors. All rights reserved.
3 | * Use of this source code is governed by a license that
4 | * can be found in the LICENSE file.
5 | */
6 | 'use strict';
7 |
8 | /**
9 | * @file Reload functions related
10 | * @author Alexandre Strzelewicz
11 | * @project PM2
12 | */
13 |
14 | var async = require('async');
15 | var cst = require('../../constants.js');
16 | var Utility = require('../Utility.js');
17 |
18 | /**
19 | * softReload will wait permission from process to exit
20 | * @method softReload
21 | * @param {} God
22 | * @param {} id
23 | * @param {} cb
24 | * @return Literal
25 | */
26 | function softReload(God, id, cb) {
27 | var t_key = '_old_' + id;
28 |
29 | // Move old worker to tmp id
30 | God.clusters_db[t_key] = God.clusters_db[id];
31 |
32 | delete God.clusters_db[id];
33 |
34 | var old_worker = God.clusters_db[t_key];
35 |
36 | // Deep copy
37 | var new_env = Utility.clone(old_worker.pm2_env);
38 | new_env.restart_time += 1;
39 |
40 | // Reset created_at and unstable_restarts
41 | God.resetState(new_env);
42 |
43 | old_worker.pm2_env.pm_id = t_key;
44 | old_worker.pm_id = t_key;
45 |
46 | God.executeApp(new_env, function(err, new_worker) {
47 | if (err) return cb(err);
48 |
49 | var timer = null;
50 |
51 | var onListen = function () {
52 | clearTimeout(timer);
53 | softCleanDeleteProcess();
54 | console.log('-softReload- New worker listening');
55 | };
56 |
57 | // Bind to know when the new process is up
58 | new_worker.once('listening', onListen);
59 |
60 | timer = setTimeout(function() {
61 | new_worker.removeListener('listening', onListen);
62 | softCleanDeleteProcess();
63 | }, new_env.listen_timeout || cst.GRACEFUL_LISTEN_TIMEOUT);
64 |
65 | // Remove old worker properly
66 | var softCleanDeleteProcess = function () {
67 | var cleanUp = function () {
68 | clearTimeout(timer);
69 | console.log('-softReload- Old worker disconnected');
70 | return God.deleteProcessId(t_key, cb);
71 | };
72 |
73 | old_worker.once('disconnect', cleanUp);
74 |
75 | try {
76 | if (old_worker.state != 'dead' && old_worker.state != 'disconnected')
77 | old_worker.send && old_worker.send('shutdown');
78 | else {
79 | clearTimeout(timer);
80 | console.error('Worker %d is already disconnected', old_worker.pm2_env.pm_id);
81 | return God.deleteProcessId(t_key, cb);
82 | }
83 | } catch(e) {
84 | clearTimeout(timer);
85 | console.error('Worker %d is already disconnected', old_worker.pm2_env.pm_id);
86 | return God.deleteProcessId(t_key, cb);
87 | }
88 |
89 | timer = setTimeout(function () {
90 | old_worker.removeListener('disconnect', cleanUp);
91 | return God.deleteProcessId(t_key, cb);
92 | }, cst.GRACEFUL_TIMEOUT);
93 | return false;
94 | };
95 | return false;
96 | });
97 | return false;
98 | };
99 |
100 | /**
101 | * hardReload will reload without waiting permission from process
102 | * @method hardReload
103 | * @param {} God
104 | * @param {} id
105 | * @param {} cb
106 | * @return Literal
107 | */
108 | function hardReload(God, id, wait_msg, cb) {
109 | var t_key = '_old_' + id;
110 |
111 | // Move old worker to tmp id
112 | God.clusters_db[t_key] = God.clusters_db[id];
113 | delete God.clusters_db[id];
114 |
115 | var old_worker = God.clusters_db[t_key];
116 | // Deep copy
117 | var new_env = Utility.clone(old_worker.pm2_env);
118 | new_env.restart_time += 1;
119 |
120 | // Reset created_at and unstable_restarts
121 | God.resetState(new_env);
122 |
123 | old_worker.pm2_env.pm_id = t_key;
124 | old_worker.pm_id = t_key;
125 |
126 | new_env.wait_ready = false;
127 |
128 | God.executeApp(new_env, function(err, new_worker) {
129 | if (err) return cb(err);
130 |
131 | var timer = null;
132 |
133 | var onListen = function () {
134 | clearTimeout(timer);
135 | console.log('-reload- New worker listening');
136 | return God.deleteProcessId(t_key, cb);
137 | };
138 |
139 | // Bind to know when the new process is up
140 | if (wait_msg == 'listening')
141 | new_worker.once('listening', onListen);
142 | else {
143 | var listener = function (packet) {
144 | if (packet.raw === 'ready' &&
145 | packet.process.name === new_worker.pm2_env.name &&
146 | packet.process.pm_id === new_worker.pm2_env.pm_id) {
147 | God.bus.removeListener('process:msg', listener)
148 | return onListen();
149 | }
150 | }
151 | God.bus.on('process:msg', listener);
152 | }
153 |
154 | timer = setTimeout(function() {
155 | if (wait_msg == 'listening')
156 | new_worker.removeListener(wait_msg, onListen);
157 | else
158 | God.bus.removeListener('process:msg', listener)
159 |
160 | return God.deleteProcessId(t_key, cb);
161 | }, new_env.listen_timeout || cst.GRACEFUL_LISTEN_TIMEOUT);
162 |
163 | return false;
164 | });
165 | return false;
166 | };
167 |
168 | /**
169 | * Description
170 | * @method exports
171 | * @param {} God
172 | * @return
173 | */
174 | module.exports = function(God) {
175 |
176 | /**
177 | * GracefulReload
178 | * @method softReloadProcessId
179 | * @param {} id
180 | * @param {} cb
181 | * @return CallExpression
182 | */
183 | God.softReloadProcessId = function(opts, cb) {
184 | var id = opts.id;
185 | var env = opts.env || {};
186 |
187 | if (!(id in God.clusters_db))
188 | return cb(new Error('PM ID unknown'));
189 |
190 | if (God.clusters_db[id].pm2_env.status == cst.ONLINE_STATUS &&
191 | God.clusters_db[id].pm2_env.exec_mode == 'cluster_mode' &&
192 | !God.clusters_db[id].pm2_env.wait_ready) {
193 |
194 | Utility.extendExtraConfig(God.clusters_db[id], opts);
195 | Utility.extend(God.clusters_db[id].pm2_env.env, opts.env);
196 |
197 | return softReload(God, id, cb);
198 | }
199 | else {
200 | console.log('Process %s in a stopped status, starting it', id);
201 | return God.restartProcessId(opts, cb);
202 | }
203 | };
204 |
205 | /**
206 | * Reload
207 | * @method reloadProcessId
208 | * @param {} id
209 | * @param {} cb
210 | * @return CallExpression
211 | */
212 | God.reloadProcessId = function(opts, cb) {
213 | var id = opts.id;
214 | var env = opts.env || {};
215 |
216 | if (!(id in God.clusters_db))
217 | return cb(new Error('PM2 ID unknown'));
218 |
219 | if (God.clusters_db[id].pm2_env.status == cst.ONLINE_STATUS &&
220 | God.clusters_db[id].pm2_env.exec_mode == 'cluster_mode') {
221 |
222 | Utility.extendExtraConfig(God.clusters_db[id], opts);
223 | Utility.extend(God.clusters_db[id].pm2_env.env, opts.env);
224 |
225 | var wait_msg = God.clusters_db[id].pm2_env.wait_ready ? 'ready' : 'listening';
226 | return hardReload(God, id, wait_msg, cb);
227 | }
228 | else {
229 | console.log('Process %s in a stopped status, starting it', id);
230 | return God.restartProcessId(opts, cb);
231 | }
232 | };
233 |
234 | };
235 |
--------------------------------------------------------------------------------
/pm2/lib/binaries/Runtime4Docker.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Specialized PM2 CLI for Containers
5 | */
6 | var commander = require('commander');
7 | var debug = require('debug')('pm2:cli');
8 | var PM2 = require('../..');
9 | var Log = require('../../lib/API/Log');
10 | var cst = require('../../constants.js');
11 | var pkg = require('../../package.json');
12 | var path = require('path');
13 | var DEFAULT_FAIL_COUNT = 3;
14 |
15 | process.env.PM2_DISCRETE_MODE = true;
16 |
17 | commander.version(pkg.version)
18 | .description('pm2-runtime is a drop-in replacement Node.js binary for containers')
19 | .option('-i --instances ', 'launch [number] of processes automatically load-balanced. Increase overall performances and performance stability.')
20 | .option('--secret [key]', '[MONITORING] keymetrics secret key')
21 | .option('--no-autorestart', 'start an app without automatic restart')
22 | .option('--node-args ', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"')
23 | .option('-n --name ', 'set a for script')
24 | .option('--max-memory-restart ', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)')
25 | .option('-c --cron ', 'restart a running process based on a cron pattern')
26 | .option('--interpreter ', 'the interpreter pm2 should use for executing app (bash, python...)')
27 | .option('--public [key]', '[MONITORING] keymetrics public key')
28 | .option('--machine-name [name]', '[MONITORING] keymetrics machine name')
29 | .option('--trace', 'enable transaction tracing with km')
30 | .option('--v8', 'enable v8 data collecting')
31 | .option('--format', 'output logs formated like key=val')
32 | .option('--raw', 'raw output (default mode)')
33 | .option('--formatted', 'formatted log output |id|app|log')
34 | .option('--json', 'output logs in json format')
35 | .option('--delay ', 'delay start of configuration file by ', 0)
36 | .option('--web [port]', 'launch process web api on [port] (default to 9615)')
37 | .option('--only ', 'only act on one application of configuration')
38 | .option('--no-auto-exit', 'do not exit if all processes are errored/stopped or 0 apps launched')
39 | .option('--env [name]', 'inject env_[name] env variables in process config file')
40 | .option('--watch', 'watch and restart application on file change')
41 | .option('--error ', 'error log file destination (default disabled)', '/dev/null')
42 | .option('--output ', 'output log file destination (default disabled)', '/dev/null')
43 | .option('--deep-monitoring', 'enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)')
44 | .allowUnknownOption()
45 | .usage('app.js');
46 |
47 | commander.command('*')
48 | .action(function(cmd){
49 | Runtime.instanciate(cmd);
50 | });
51 |
52 | commander.command('start ')
53 | .description('start an application or json ecosystem file')
54 | .action(function(cmd) {
55 | Runtime.instanciate(cmd);
56 | });
57 |
58 | if (process.argv.length == 2) {
59 | commander.outputHelp();
60 | process.exit(1);
61 | }
62 |
63 | var Runtime = {
64 | pm2 : null,
65 | instanciate : function(cmd) {
66 | this.pm2 = new PM2.custom({
67 | pm2_home : process.env.PM2_HOME || path.join(process.env.HOME, '.pm2'),
68 | secret_key : process.env.KEYMETRICS_SECRET || commander.secret,
69 | public_key : process.env.KEYMETRICS_PUBLIC || commander.public,
70 | machine_name : process.env.INSTANCE_NAME || commander.machineName,
71 | daemon_mode : process.env.PM2_RUNTIME_DEBUG || false
72 | });
73 |
74 | this.pm2.connect(function(err, pm2_meta) {
75 | if (pm2_meta.new_pm2_instance == false) {
76 | console.warn('[WARN] PM2 Daemon is already running')
77 | }
78 |
79 | process.on('SIGINT', function() {
80 | Runtime.exit();
81 | });
82 |
83 | process.on('SIGTERM', function() {
84 | Runtime.exit();
85 | });
86 |
87 | Runtime.startLogStreaming();
88 | Runtime.startApp(cmd, function(err) {
89 | if (err) {
90 | console.error(err.message || err);
91 | return Runtime.exit();
92 | }
93 | });
94 | });
95 | },
96 |
97 | /**
98 | * Log Streaming Management
99 | */
100 | startLogStreaming : function() {
101 | if (commander.json === true)
102 | Log.jsonStream(this.pm2.Client, 'all');
103 | else if (commander.format === true)
104 | Log.formatStream(this.pm2.Client, 'all', false, 'YYYY-MM-DD-HH:mm:ssZZ');
105 | else
106 | Log.stream(this.pm2.Client, 'all', !commander.formatted, commander.timestamp, true);
107 | },
108 |
109 | /**
110 | * Application Startup
111 | */
112 | startApp : function(cmd, cb) {
113 | function exec() {
114 | this.pm2.start(cmd, commander, function(err, obj) {
115 | if (err)
116 | return cb(err);
117 | if (obj && obj.length == 0)
118 | return cb(new Error('Failed to start application'))
119 |
120 | if (commander.web) {
121 | var port = commander.web === true ? cst.WEB_PORT : commander.web;
122 | Runtime.pm2.web(port);
123 | }
124 |
125 | if (commander.autoExit) {
126 | setTimeout(function() {
127 | Runtime.autoExitWorker();
128 | }, 4000);
129 | }
130 |
131 | // For Testing purpose (allow to auto exit CLI)
132 | if (process.env.PM2_RUNTIME_DEBUG)
133 | Runtime.pm2.disconnect(function() {});
134 |
135 | return cb(null, obj);
136 | });
137 | }
138 | // via --delay option
139 | setTimeout(exec.bind(this), commander.delay * 1000);
140 | },
141 |
142 | /**
143 | * Exit runtime mgmt
144 | */
145 | exit : function(code) {
146 | if (!this.pm2) return process.exit(1);
147 |
148 | this.pm2.kill(function() {
149 | process.exit(code || 0);
150 | });
151 | },
152 |
153 | /**
154 | * Exit current PM2 instance if 0 app is online
155 | * function activated via --auto-exit
156 | */
157 | autoExitWorker : function(fail_count) {
158 | var interval = 2000;
159 |
160 | if (typeof(fail_count) =='undefined')
161 | fail_count = DEFAULT_FAIL_COUNT;
162 |
163 | var timer = setTimeout(function () {
164 | Runtime.pm2.list(function (err, apps) {
165 | if (err) {
166 | console.error('Could not run pm2 list');
167 | return Runtime.autoExitWorker();
168 | }
169 |
170 | var appOnline = 0;
171 |
172 | apps.forEach(function (app) {
173 | if (app.pm2_env.status === cst.ONLINE_STATUS ||
174 | app.pm2_env.status === cst.LAUNCHING_STATUS) {
175 | appOnline++;
176 | }
177 | });
178 |
179 | if (appOnline === 0) {
180 | console.log('0 application online, retry =', fail_count);
181 | if (fail_count <= 0)
182 | return Runtime.exit(2);
183 | return Runtime.autoExitWorker(--fail_count);
184 | }
185 |
186 | Runtime.autoExitWorker();
187 | });
188 | }, interval);
189 |
190 | timer.unref();
191 | }
192 | }
193 |
194 | commander.parse(process.argv);
195 |
--------------------------------------------------------------------------------