pm2-perfmonitor 1.1.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,15 +17,16 @@ $ pm2 install pm2-perfmonitor
17
17
 
18
18
  # Configure
19
19
 
20
- | Property | Default Value | Description |
21
- | :-----------------------------: | :-----------: | :----------------------------------------------------------------------: |
22
- | `enabled` | `true` | Specify whether to enable this module |
23
- | `excludeApps` | - | Specify the application name that needs to be excluded from guardianship |
24
- | `includeApps` | - | Specify the application name that needs to be guarded |
25
- | `workerInterval` | `60000` | Timed task execution interval (ms) |
26
- | `zombieDetection` | `true` | Specify whether to enable zombie process protection |
27
- | `zombieMaxHits` | `10` | Specify the maximum occurrence frequency of zombie status |
28
- | `autoRestartWhenZombieDetected` | `true` | Specify whether to automatically restart zombie processes |
20
+ | Property | Default Value | Description |
21
+ | :-----------------------------: | :-----------: | :----------------------------------------------------------------------------------: |
22
+ | `enabled` | `true` | Specify whether to enable this module |
23
+ | `excludeApps` | - | Specify the application name that needs to be excluded from guardianship |
24
+ | `includeApps` | - | Specify the application name that needs to be guarded |
25
+ | `workerInterval` | `60000` | Timed task execution interval (ms) |
26
+ | `zombieDetection` | `true` | Specify whether to enable zombie process protection |
27
+ | `zombieMaxHits` | `10` | Specify the maximum occurrence frequency of zombie status |
28
+ | `autoRestartWhenZombieDetected` | `true` | Specify whether to automatically restart zombie processes |
29
+ | `zombieMaxRestarts` | `0` | The maximum number of zombie process restarts can be set to `0` to indicate no limit |
29
30
 
30
31
  # How to set these values ?
31
32
 
package/lib/app.js CHANGED
@@ -1,34 +1,9 @@
1
1
  const pmx = require('pmx')
2
2
  const pm2 = require('pm2')
3
+ const { listAppsAsync } = require('./pm2-extra')
3
4
  const { parseParamToArray, parseParamToNumber, parseBool } = require('./utils')
4
-
5
- const defaultOptions = {
6
- enabled: true,
7
- /**
8
- * 排除的 app 名
9
- */
10
- excludeApps: [],
11
- /**
12
- * 包含的 app 名
13
- */
14
- includeApps: [],
15
- /**
16
- * 定时检测间隔(ms)
17
- */
18
- workerInterval: 60000,
19
- /**
20
- * 是否开启僵尸进程守护
21
- */
22
- zombieDetection: true,
23
- /**
24
- * 僵尸状态最大出现次数
25
- */
26
- zombieMaxHits: 10,
27
- /**
28
- * 僵尸状态达到最大容忍度时,是否自动重启僵尸进程
29
- */
30
- autoRestartWhenZombieDetected: true,
31
- }
5
+ const { defaultOptions } = require('./defaults')
6
+ // const { sendMessage } = require('./message')
32
7
 
33
8
  const conf = pmx.initModule({}, (err, incomingConf) => {
34
9
  if (err) {
@@ -53,6 +28,7 @@ const AUTO_RESTART_WHEN_ZOMBIE_DETECTED = parseBool(
53
28
  conf.autoRestartWhenZombieDetected,
54
29
  )
55
30
  const ZOMBIE_MAX_HITS = parseParamToNumber(conf.zombieMaxHits)
31
+ const ZOMBIE_MAX_RESTARTS = parseParamToNumber(conf.zombieMaxRestarts)
56
32
 
57
33
  // 存储每个进程的 CPU 采样历史(pm_id -> [cpu1, cpu2, ...])
58
34
  const cpuHistory = new Map()
@@ -69,6 +45,7 @@ const logger = (type, ...args) => {
69
45
 
70
46
  /**
71
47
  * 判断是否为僵尸进程:最近 ZOMBIE_MAX_HITS 次全是 0%
48
+ * @param { number[] } history
72
49
  */
73
50
  const isZombie = (history) => {
74
51
  return history.length >= ZOMBIE_MAX_HITS && history.every((v) => v === 0)
@@ -77,16 +54,19 @@ const isZombie = (history) => {
77
54
  /**
78
55
  * check zombie process
79
56
  */
80
- const zombieProcessChecker = () => {
57
+ const zombieProcessChecker = async () => {
81
58
  if (!ZOMBIE_DETECTION) return
82
59
 
83
- pm2.list((err, apps) => {
60
+ try {
61
+ const apps = await listAppsAsync()
62
+
84
63
  apps.forEach((app) => {
85
64
  const { name, pm_id, monit, pm2_env } = app
86
65
 
87
66
  const appStatus = pm2_env?.status
88
67
  const appCpuUsage = monit?.cpu || 0
89
68
 
69
+ // 非目标应用,跳过
90
70
  if (
91
71
  MODULE_NAME === name ||
92
72
  (INCLUDE_APPS.length > 0 && !INCLUDE_APPS.includes(name)) ||
@@ -95,7 +75,7 @@ const zombieProcessChecker = () => {
95
75
  return
96
76
  }
97
77
 
98
- // 2. 只处理 online 状态的进程
78
+ // 只处理 online 状态的进程
99
79
  if (appStatus !== 'online') {
100
80
  // 进程不在 online 状态时,清空其历史记录,避免干扰
101
81
  cpuHistory.delete(pm_id)
@@ -115,12 +95,21 @@ const zombieProcessChecker = () => {
115
95
  history.shift()
116
96
  }
117
97
 
118
- // 4. 判断是否为僵尸:最近 ZOMBIE_MAX_HITS 次全是 0%
119
-
98
+ // 判断是否为僵尸:最近 ZOMBIE_MAX_HITS 次全是 0%
120
99
  if (isZombie(history)) {
121
- logger('info', `Zombie detected: ${name} (pm_id: ${pm_id})`)
100
+ logger(
101
+ 'info',
102
+ `Zombie detected: ${name} (pm_id: ${pm_id}, pid: ${app.pid})`,
103
+ )
122
104
 
123
105
  if (AUTO_RESTART_WHEN_ZOMBIE_DETECTED) {
106
+ if (
107
+ ZOMBIE_MAX_RESTARTS > 0 &&
108
+ zombieRestartHistory.get(pm_id) >= ZOMBIE_MAX_RESTARTS
109
+ ) {
110
+ return
111
+ }
112
+
124
113
  logger('info', 'restarting...')
125
114
 
126
115
  pm2.restart(pm_id, (restartErr) => {
@@ -162,7 +151,9 @@ const zombieProcessChecker = () => {
162
151
  }
163
152
  }
164
153
  })
165
- })
154
+ } catch (err) {
155
+ logger('error', err)
156
+ }
166
157
  }
167
158
 
168
159
  const runModule = () => {
@@ -0,0 +1,35 @@
1
+ const defaultOptions = {
2
+ enabled: true,
3
+ /**
4
+ * 排除的 app 名
5
+ */
6
+ excludeApps: [],
7
+ /**
8
+ * 包含的 app 名
9
+ */
10
+ includeApps: [],
11
+ /**
12
+ * 定时检测间隔(ms)
13
+ */
14
+ workerInterval: 60000,
15
+ /**
16
+ * 是否开启僵尸进程守护
17
+ */
18
+ zombieDetection: true,
19
+ /**
20
+ * 僵尸状态最大出现次数
21
+ */
22
+ zombieMaxHits: 10,
23
+ /**
24
+ * 僵尸状态达到最大容忍度时,是否自动重启僵尸进程
25
+ */
26
+ autoRestartWhenZombieDetected: true,
27
+ /**
28
+ * 僵尸进程最大重启次数,设置为0表示不限制
29
+ */
30
+ zombieMaxRestarts: 0,
31
+ }
32
+
33
+ module.exports = {
34
+ defaultOptions,
35
+ }
package/lib/message.js ADDED
@@ -0,0 +1,22 @@
1
+ const pm2 = require('pm2')
2
+
3
+ /**
4
+ * @param { number } pid 进程id
5
+ * @param { string } eventName 事件名
6
+ * @param { Object } data
7
+ */
8
+ const sendMessage = (pid, eventName, data) => {
9
+ pm2.sendDataToProcessId(pid, {
10
+ id: pid,
11
+ type: 'process:msg',
12
+ topic: true,
13
+ data: {
14
+ event: `pm2-perfmonitor:${eventName}`,
15
+ data,
16
+ },
17
+ })
18
+ }
19
+
20
+ module.exports = {
21
+ sendMessage,
22
+ }
@@ -0,0 +1,37 @@
1
+ const pm2 = require('pm2')
2
+
3
+ /**
4
+ * @returns { Promise<pm2.ProcessDescription[]> }
5
+ */
6
+ const listAppsAsync = () => {
7
+ return new Promise((resolve, reject) => {
8
+ pm2.list((err, apps) => {
9
+ if (err) {
10
+ return reject(err)
11
+ }
12
+
13
+ resolve(apps)
14
+ })
15
+ })
16
+ }
17
+
18
+ /**
19
+ * @param { string | number} pm_id
20
+ * @returns { Promise<void> }
21
+ */
22
+ const stopAppAsync = (pm_id) => {
23
+ return new Promise((resolve, reject) => {
24
+ pm2.stop(pm_id, (err) => {
25
+ if (err) {
26
+ return reject(err)
27
+ }
28
+
29
+ resolve()
30
+ })
31
+ })
32
+ }
33
+
34
+ module.exports = {
35
+ listAppsAsync,
36
+ stopAppAsync,
37
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pm2-perfmonitor",
3
- "version": "1.1.2",
3
+ "version": "1.2.3",
4
4
  "description": "A pm2 module for performance monitoring. Automatically detect zombie processes and restart it",
5
5
  "author": {
6
6
  "name": "elenh",
@@ -20,8 +20,12 @@
20
20
  },
21
21
  "homepage": "https://github.com/yisibell/pm2-perfmonitor",
22
22
  "scripts": {
23
- "start": "pm2 delete app1 || true && pm2 start ecosystem.app.config.cjs",
24
- "dev": "pm2 start ecosystem.dev.config.cjs",
23
+ "start-or-restart:app": "pm2 startOrRestart ecosystem.app.config.cjs --update-env",
24
+ "start:app": "pm2 start ecosystem.app.config.cjs",
25
+ "restart:app": "pm2 restart ecosystem.app.config.cjs",
26
+ "delete-start:app": "pm2 delete app1 || true && pm2 start ecosystem.app.config.cjs",
27
+ "start": "node ./scripts/app.js --env=app",
28
+ "dev": "pm2 restart ecosystem.dev.config.cjs",
25
29
  "release": "changelogen --release && npm publish --access=public && git push --follow-tags"
26
30
  },
27
31
  "keywords": [
@@ -43,6 +47,7 @@
43
47
  },
44
48
  "devDependencies": {
45
49
  "changelogen": "^0.6.2",
46
- "cz-conventional-changelog": "^3.3.0"
50
+ "cz-conventional-changelog": "^3.3.0",
51
+ "minimist": "^1.2.8"
47
52
  }
48
53
  }