topbit 3.0.8 → 3.1.1
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.cn.md +2 -2
- package/README.md +2 -2
- package/demo/allow.js +28 -8
- package/demo/group-api.js +1 -1
- package/demo/group-api2.js +1 -1
- package/demo/monitor.js +81 -0
- package/package.json +1 -1
- package/src/extends/Http2Pool.js +143 -309
- package/src/extends/http2proxy.js +39 -141
- package/src/extends/proxy.js +16 -17
- package/src/monitor.js +102 -90
- package/src/topbit.js +8 -8
- package/test/test-route-sort.js +1 -1
- package/test/test-route2.js +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const http2 = require('node:http2')
|
|
4
|
-
const Http2Pool = require('./Http2Pool')
|
|
4
|
+
const Http2Pool = require('./Http2Pool.js')
|
|
5
5
|
|
|
6
6
|
let error_502_text = `<!DOCTYPE html><html>
|
|
7
7
|
<head>
|
|
@@ -52,6 +52,19 @@ function fmtpath(path) {
|
|
|
52
52
|
return `${path}*`
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
// 主机名提取 (IPv6 兼容优化版)
|
|
56
|
+
function extractHostname(host) {
|
|
57
|
+
if (!host) return ''
|
|
58
|
+
if (host.charCodeAt(0) === 91) { // '[' IPv6
|
|
59
|
+
const end = host.indexOf(']')
|
|
60
|
+
return end > -1 ? host.substring(0, end + 1) : host
|
|
61
|
+
}
|
|
62
|
+
const idx = host.indexOf(':')
|
|
63
|
+
if (idx === -1) return host
|
|
64
|
+
if (host.indexOf(':', idx + 1) !== -1) return host // 裸 IPv6
|
|
65
|
+
return host.substring(0, idx)
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
let Http2Proxy = function (options = {}) {
|
|
56
69
|
|
|
57
70
|
if (!(this instanceof Http2Proxy)) return Http2Proxy(options)
|
|
@@ -188,8 +201,8 @@ Http2Proxy.prototype.checkAndSetConfig = function (backend_obj, tmp) {
|
|
|
188
201
|
|
|
189
202
|
}
|
|
190
203
|
|
|
191
|
-
if (tmp.
|
|
192
|
-
backend_obj.
|
|
204
|
+
if (tmp.maxConnect && typeof tmp.maxConnect === 'number' && tmp.maxConnect > 1)
|
|
205
|
+
backend_obj.maxConnect = tmp.maxConnect
|
|
193
206
|
|
|
194
207
|
if (tmp.debug !== undefined) backend_obj.debug = tmp.debug
|
|
195
208
|
|
|
@@ -244,8 +257,7 @@ Http2Proxy.prototype.setHostProxy = function (cfg) {
|
|
|
244
257
|
weight: 1,
|
|
245
258
|
weightCount: 0,
|
|
246
259
|
reconnDelay: 500,
|
|
247
|
-
|
|
248
|
-
maxConnect: tmp.maxConnect || 0,
|
|
260
|
+
maxConnect: tmp.maxConnect || 10,
|
|
249
261
|
debug: this.debug,
|
|
250
262
|
h2Pool: null,
|
|
251
263
|
timeout: this.timeout,
|
|
@@ -268,7 +280,6 @@ Http2Proxy.prototype.setHostProxy = function (cfg) {
|
|
|
268
280
|
|
|
269
281
|
backend_obj.h2Pool = new Http2Pool({
|
|
270
282
|
debug: backend_obj.debug,
|
|
271
|
-
max: backend_obj.max,
|
|
272
283
|
url: backend_obj.url,
|
|
273
284
|
connectOptions: backend_obj.connectOptions,
|
|
274
285
|
parent: backend_obj,
|
|
@@ -338,23 +349,6 @@ Http2Proxy.prototype.getBackend = function (c, host) {
|
|
|
338
349
|
}
|
|
339
350
|
}
|
|
340
351
|
|
|
341
|
-
if (!pr.alive) {
|
|
342
|
-
pr.h2Pool && pr.h2Pool.delayConnect()
|
|
343
|
-
|
|
344
|
-
for (let i = prlist.length - 1; i >= 0 ; i--) {
|
|
345
|
-
|
|
346
|
-
pr = prlist[i]
|
|
347
|
-
|
|
348
|
-
if (pr.alive) {
|
|
349
|
-
return pr
|
|
350
|
-
} else {
|
|
351
|
-
pr.h2Pool && pr.h2Pool.delayConnect()
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return null
|
|
356
|
-
}
|
|
357
|
-
|
|
358
352
|
return pr
|
|
359
353
|
}
|
|
360
354
|
|
|
@@ -401,22 +395,7 @@ Http2Proxy.prototype.mid = function () {
|
|
|
401
395
|
|
|
402
396
|
return async (c, next) => {
|
|
403
397
|
|
|
404
|
-
let host = c.host
|
|
405
|
-
|
|
406
|
-
let hind = c.host.length - 1
|
|
407
|
-
|
|
408
|
-
if (hind > 4) {
|
|
409
|
-
let eind = hind - 5
|
|
410
|
-
|
|
411
|
-
while (hind >= eind) {
|
|
412
|
-
if (c.host[hind] === ':') {
|
|
413
|
-
host = c.host.substring(0, hind)
|
|
414
|
-
break
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
hind--
|
|
418
|
-
}
|
|
419
|
-
}
|
|
398
|
+
let host = extractHostname(c.host)
|
|
420
399
|
|
|
421
400
|
if (!self.hostProxy[host] || !self.hostProxy[host][c.routepath]) {
|
|
422
401
|
if (self.full) {
|
|
@@ -427,25 +406,7 @@ Http2Proxy.prototype.mid = function () {
|
|
|
427
406
|
}
|
|
428
407
|
|
|
429
408
|
let pr = self.getBackend(c, host)
|
|
430
|
-
|
|
431
|
-
if (!pr) {
|
|
432
|
-
pr = self.getBackend(c, host)
|
|
433
|
-
|
|
434
|
-
if (!pr) {
|
|
435
|
-
await c.ext.delay(9)
|
|
436
|
-
pr = self.getBackend(c, host)
|
|
437
|
-
|
|
438
|
-
if (!pr) {
|
|
439
|
-
for (let i = 0; i < 200; i++) {
|
|
440
|
-
await c.ext.delay(6 + i)
|
|
441
|
-
pr = self.getBackend(c, host)
|
|
442
|
-
if (pr) break
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
if (!pr) return c.status(503).to(error_503_text)
|
|
447
|
-
}
|
|
448
|
-
}
|
|
409
|
+
if (!pr) return c.status(503).to(error_503_text)
|
|
449
410
|
|
|
450
411
|
if (self.addIP && c.headers['x-real-ip']) {
|
|
451
412
|
c.headers['x-real-ip'] += `,${c.ip}`
|
|
@@ -454,7 +415,6 @@ Http2Proxy.prototype.mid = function () {
|
|
|
454
415
|
}
|
|
455
416
|
|
|
456
417
|
let hii = pr.h2Pool
|
|
457
|
-
let session_client
|
|
458
418
|
|
|
459
419
|
try {
|
|
460
420
|
if (pr.headers) {
|
|
@@ -462,73 +422,38 @@ Http2Proxy.prototype.mid = function () {
|
|
|
462
422
|
}
|
|
463
423
|
|
|
464
424
|
if (pr.rewrite) {
|
|
465
|
-
let rpath = pr.rewrite(c, c.major
|
|
425
|
+
let rpath = pr.rewrite(c, c.major > 1 ? c.headers[':path'] : c.req.url)
|
|
466
426
|
|
|
467
427
|
if (rpath) {
|
|
468
428
|
let path_typ = typeof rpath
|
|
469
429
|
if (path_typ === 'object' && rpath.redirect) {
|
|
470
430
|
return c.setHeader('location', rpath.redirect)
|
|
471
431
|
} else if (path_typ === 'string') {
|
|
472
|
-
c.
|
|
432
|
+
if (c.major > 1)
|
|
433
|
+
c.headers[':path'] = rpath
|
|
434
|
+
else c.req.url = rpath
|
|
473
435
|
}
|
|
474
436
|
}
|
|
475
437
|
}
|
|
476
438
|
|
|
477
|
-
session_client = await hii.getSession()
|
|
478
|
-
|
|
479
|
-
if (session_client.deny) {
|
|
480
|
-
for (let i = 0; i < 50; i++) {
|
|
481
|
-
await c.ext.delay(5 + i)
|
|
482
|
-
session_client = await hii.getSession()
|
|
483
|
-
if (!session_client.deny) break
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
if (session_client.deny)
|
|
487
|
-
return c.status(429).to('服务繁忙,请稍后再试')
|
|
488
|
-
}
|
|
489
|
-
|
|
490
439
|
await new Promise(async (rv, rj) => {
|
|
491
440
|
let resolved = false
|
|
492
441
|
let rejected = false
|
|
493
442
|
let request_stream = c.stream
|
|
494
443
|
let stm = null
|
|
495
444
|
|
|
496
|
-
stm = await hii.request(
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
stm = null
|
|
503
|
-
})
|
|
445
|
+
stm = await hii.request(c.major > 1 ? c.headers : this.fmtHeaders(c.headers, c))
|
|
446
|
+
.catch(err => {
|
|
447
|
+
rejected = true
|
|
448
|
+
rj(err)
|
|
449
|
+
stm = null
|
|
450
|
+
})
|
|
504
451
|
|
|
505
452
|
if (!stm) {
|
|
506
453
|
rj(new Error('request failed'))
|
|
507
454
|
return false
|
|
508
455
|
}
|
|
509
456
|
|
|
510
|
-
let timeout_handler = () => {
|
|
511
|
-
timeout_timer = null
|
|
512
|
-
|
|
513
|
-
//强制的异常结束,这意味着session的其他stream也会出现问题。
|
|
514
|
-
try {
|
|
515
|
-
!stm.closed && stm.close(http2.constants.NGHTTP2_CANCEL)
|
|
516
|
-
stm.destroy()
|
|
517
|
-
if (session_client.session && !session_client.session.destroyed) {
|
|
518
|
-
session_client.session.destroy()
|
|
519
|
-
}
|
|
520
|
-
} catch(e) {}
|
|
521
|
-
|
|
522
|
-
if (!resolved && !rejected) {
|
|
523
|
-
rejected = true
|
|
524
|
-
rj(new Error('force destroy stream, request timeout'))
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
session_client.aliveStreams++
|
|
529
|
-
|
|
530
|
-
let timeout_timer = setTimeout(timeout_handler, pr.timeout + 5000)
|
|
531
|
-
|
|
532
457
|
c.stream.on('timeout', () => {
|
|
533
458
|
stm.close(http2.constants.NGHTTP2_CANCEL)
|
|
534
459
|
//stm.destroy()
|
|
@@ -541,11 +466,6 @@ Http2Proxy.prototype.mid = function () {
|
|
|
541
466
|
})
|
|
542
467
|
|
|
543
468
|
c.stream.on('error', err => {
|
|
544
|
-
if (timeout_timer) {
|
|
545
|
-
clearTimeout(timeout_timer)
|
|
546
|
-
timeout_timer = null
|
|
547
|
-
}
|
|
548
|
-
|
|
549
469
|
stm.close(http2.constants.NGHTTP2_INTERNAL_ERROR)
|
|
550
470
|
stm.destroy()
|
|
551
471
|
})
|
|
@@ -562,11 +482,6 @@ Http2Proxy.prototype.mid = function () {
|
|
|
562
482
|
})
|
|
563
483
|
|
|
564
484
|
stm.on('aborted', err => {
|
|
565
|
-
if (timeout_timer) {
|
|
566
|
-
clearTimeout(timeout_timer)
|
|
567
|
-
timeout_timer = null
|
|
568
|
-
}
|
|
569
|
-
|
|
570
485
|
!stm.destroyed && stm.destroy()
|
|
571
486
|
|
|
572
487
|
if (!resolved && !rejected) {
|
|
@@ -576,13 +491,6 @@ Http2Proxy.prototype.mid = function () {
|
|
|
576
491
|
})
|
|
577
492
|
|
|
578
493
|
stm.on('close', () => {
|
|
579
|
-
if (timeout_timer) {
|
|
580
|
-
clearTimeout(timeout_timer)
|
|
581
|
-
timeout_timer = null
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
stm.removeAllListeners()
|
|
585
|
-
|
|
586
494
|
if (stm.rstCode === http2.constants.NGHTTP2_NO_ERROR) {
|
|
587
495
|
if (!resolved && !rejected) {
|
|
588
496
|
resolved = true
|
|
@@ -594,13 +502,9 @@ Http2Proxy.prototype.mid = function () {
|
|
|
594
502
|
rj(new Error(`stream close, exit code ${stm.rstCode}`))
|
|
595
503
|
}
|
|
596
504
|
}
|
|
597
|
-
|
|
598
|
-
session_client.aliveStreams--
|
|
599
505
|
})
|
|
600
506
|
|
|
601
507
|
stm.on('response', (headers, flags) => {
|
|
602
|
-
timeout_timer && clearTimeout(timeout_timer)
|
|
603
|
-
timeout_timer = setTimeout(timeout_handler, pr.timeout + 5000)
|
|
604
508
|
if (c.res && c.res.writable) {
|
|
605
509
|
if (c.res.respond) {
|
|
606
510
|
c.res.respond(headers)
|
|
@@ -636,25 +540,21 @@ Http2Proxy.prototype.mid = function () {
|
|
|
636
540
|
stm.end()
|
|
637
541
|
})
|
|
638
542
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
data_count++
|
|
642
|
-
c.res && c.res.writable && c.res.write(chunk)
|
|
543
|
+
const onDrain = () => stm.resume()
|
|
544
|
+
if (c.res) c.res.on('drain', onDrain)
|
|
643
545
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
546
|
+
stm.on('data', chunk => {
|
|
547
|
+
if (c.res && c.res.writable) {
|
|
548
|
+
if (c.res.write(chunk) === false) {
|
|
549
|
+
stm.pause()
|
|
550
|
+
}
|
|
648
551
|
}
|
|
649
552
|
})
|
|
650
553
|
|
|
651
554
|
stm.on('end', () => {
|
|
652
|
-
if (
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
stm.close()
|
|
555
|
+
if (c.res) c.res.removeListener('drain', onDrain)
|
|
556
|
+
|
|
557
|
+
!stm.closed && stm.close()
|
|
658
558
|
|
|
659
559
|
if (!resolved && !rejected) {
|
|
660
560
|
resolved = true
|
|
@@ -666,8 +566,6 @@ Http2Proxy.prototype.mid = function () {
|
|
|
666
566
|
} catch (err) {
|
|
667
567
|
self.debug && console.error(err||'request null error')
|
|
668
568
|
c.status(503).to(error_503_text)
|
|
669
|
-
} finally {
|
|
670
|
-
session_client = null
|
|
671
569
|
}
|
|
672
570
|
|
|
673
571
|
}
|
package/src/extends/proxy.js
CHANGED
|
@@ -4,6 +4,20 @@ const urlparse = require('node:url');
|
|
|
4
4
|
const http = require('node:http');
|
|
5
5
|
const https = require('node:https');
|
|
6
6
|
|
|
7
|
+
// 主机名提取 (IPv6 兼容优化版)
|
|
8
|
+
function extractHostname(host) {
|
|
9
|
+
if (!host) return ''
|
|
10
|
+
if (host.charCodeAt(0) === 91) { // '[' IPv6
|
|
11
|
+
const end = host.indexOf(']')
|
|
12
|
+
return end > -1 ? host.substring(0, end + 1) : host
|
|
13
|
+
}
|
|
14
|
+
const idx = host.indexOf(':')
|
|
15
|
+
if (idx === -1) return host
|
|
16
|
+
if (host.indexOf(':', idx + 1) !== -1) return host // 裸 IPv6
|
|
17
|
+
return host.substring(0, idx)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
7
21
|
/**
|
|
8
22
|
* {
|
|
9
23
|
* host : {}
|
|
@@ -406,22 +420,7 @@ class Proxy {
|
|
|
406
420
|
|
|
407
421
|
return async (c, next) => {
|
|
408
422
|
|
|
409
|
-
let host = c.host
|
|
410
|
-
|
|
411
|
-
let hind = c.host.length - 1
|
|
412
|
-
|
|
413
|
-
if (hind > 4) {
|
|
414
|
-
let eind = hind - 5
|
|
415
|
-
|
|
416
|
-
while (hind >= eind) {
|
|
417
|
-
if (c.host[hind] === ':') {
|
|
418
|
-
host = c.host.substring(0, hind)
|
|
419
|
-
break
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
hind--
|
|
423
|
-
}
|
|
424
|
-
}
|
|
423
|
+
let host = extractHostname(c.host)
|
|
425
424
|
|
|
426
425
|
if (self.hostProxy[host]===undefined || self.hostProxy[host][c.routepath]===undefined) {
|
|
427
426
|
if (self.full) {
|
|
@@ -433,7 +432,7 @@ class Proxy {
|
|
|
433
432
|
let pr = self.getBackend(c, host)
|
|
434
433
|
|
|
435
434
|
if (pr === null) {
|
|
436
|
-
for (let i = 0; i <
|
|
435
|
+
for (let i = 0; i < 50; i++) {
|
|
437
436
|
await new Promise((rv, rj) => {setTimeout(rv, 10)})
|
|
438
437
|
pr = self.getBackend(c, host)
|
|
439
438
|
if (pr) break
|
package/src/monitor.js
CHANGED
|
@@ -5,6 +5,8 @@ const os = require('node:os');
|
|
|
5
5
|
const fs = require('node:fs');
|
|
6
6
|
const process = require('node:process');
|
|
7
7
|
|
|
8
|
+
const hrtime = process.hrtime
|
|
9
|
+
|
|
8
10
|
class Monitor {
|
|
9
11
|
|
|
10
12
|
constructor(options) {
|
|
@@ -15,6 +17,8 @@ class Monitor {
|
|
|
15
17
|
|
|
16
18
|
this.workerCount = options.workerCount
|
|
17
19
|
|
|
20
|
+
this.isLoadObj = ['obj', 'orgobj'].includes(this.config.loadInfoType)
|
|
21
|
+
|
|
18
22
|
this.rundata.cpus = os.cpus().length
|
|
19
23
|
|
|
20
24
|
this.loadCount = 0
|
|
@@ -24,9 +28,9 @@ class Monitor {
|
|
|
24
28
|
|
|
25
29
|
this.loadCache = null
|
|
26
30
|
|
|
27
|
-
this.cpuLastTime =
|
|
31
|
+
this.cpuLastTime = hrtime.bigint() - 1n
|
|
28
32
|
|
|
29
|
-
this.cpuNowTime =
|
|
33
|
+
this.cpuNowTime = hrtime.bigint()
|
|
30
34
|
|
|
31
35
|
//this.cpuPercentFactor = 10 * this.rundata.cpus;
|
|
32
36
|
this.cpuHighRatio = 0
|
|
@@ -45,10 +49,36 @@ class Monitor {
|
|
|
45
49
|
|
|
46
50
|
this.life = 20
|
|
47
51
|
|
|
48
|
-
this.maxRate =
|
|
52
|
+
this.maxRate = this.config.maxLoadRate
|
|
49
53
|
|
|
50
54
|
this.loadfd = null
|
|
51
55
|
|
|
56
|
+
this.ipcMsgCache = {
|
|
57
|
+
type: '_load',
|
|
58
|
+
pid: 0,
|
|
59
|
+
cpu: null,
|
|
60
|
+
cputm: 0,
|
|
61
|
+
mem: null,
|
|
62
|
+
conn: 0
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.loadjson = {
|
|
66
|
+
masterPid : process.pid,
|
|
67
|
+
listen : `${this.rundata.host}:${this.rundata.port}`,
|
|
68
|
+
CPULoadavg : {
|
|
69
|
+
'1m' : '0',
|
|
70
|
+
'5m' : '0',
|
|
71
|
+
'15m' : '0'
|
|
72
|
+
},
|
|
73
|
+
https: this.config.https,
|
|
74
|
+
http2: this.config.http2,
|
|
75
|
+
workers : []
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
queueMicrotask(() => {
|
|
79
|
+
this.loadjson.listen = `${this.rundata.host}:${this.rundata.port}`
|
|
80
|
+
})
|
|
81
|
+
|
|
52
82
|
}
|
|
53
83
|
|
|
54
84
|
autoWorker() {
|
|
@@ -65,20 +95,20 @@ class Monitor {
|
|
|
65
95
|
for (let k in this.workers) {
|
|
66
96
|
cpuratio = (this.workers[k].cpu.user + this.workers[k].cpu.system) / this.workers[k].cputm
|
|
67
97
|
|
|
68
|
-
if (cpuratio
|
|
69
|
-
this.cpuHighRatio
|
|
98
|
+
if (cpuratio > this.maxRate) {
|
|
99
|
+
this.cpuHighRatio++
|
|
70
100
|
} else {
|
|
71
101
|
if (this.cpuHighRatio > 0) {
|
|
72
|
-
this.cpuHighRatio
|
|
102
|
+
this.cpuHighRatio--
|
|
73
103
|
}
|
|
104
|
+
|
|
74
105
|
break
|
|
75
106
|
}
|
|
76
107
|
}
|
|
77
108
|
}
|
|
78
109
|
|
|
79
110
|
if (this.cpuHighRatio >= this.workerCount.cur) {
|
|
80
|
-
|
|
81
|
-
this.cpuHighRatio -= 1
|
|
111
|
+
this.cpuHighRatio--
|
|
82
112
|
|
|
83
113
|
if (this.workerCount.cur < this.workerCount.max) {
|
|
84
114
|
if (this.workerCount.canAutoFork) {
|
|
@@ -106,7 +136,7 @@ class Monitor {
|
|
|
106
136
|
|
|
107
137
|
if (this.workerCount.cur > this.workerCount.total) {
|
|
108
138
|
if (this.cooling > 0) {
|
|
109
|
-
this.cooling
|
|
139
|
+
this.cooling--
|
|
110
140
|
} else {
|
|
111
141
|
for (let k in this.workers) {
|
|
112
142
|
if (this.workers[k].conn === 0) {
|
|
@@ -169,12 +199,16 @@ class Monitor {
|
|
|
169
199
|
if (will_disconnect) return;
|
|
170
200
|
|
|
171
201
|
this.cpuLastTime = this.cpuNowTime
|
|
172
|
-
this.cpuNowTime =
|
|
202
|
+
this.cpuNowTime = hrtime.bigint()
|
|
203
|
+
let diffNs = this.cpuNowTime - this.cpuLastTime
|
|
204
|
+
let diffUs = (Number(diffNs) / 1000) + 0.01
|
|
173
205
|
|
|
206
|
+
//此处是计算微秒的cpu变化,而计算负载正好按照微秒进行
|
|
174
207
|
this.rundata.cpuTime = process.cpuUsage(this.rundata.cpuLast)
|
|
208
|
+
|
|
175
209
|
if (mem_count < MAX_MEM_COUNT) {
|
|
176
210
|
this.rundata.mem.rss = process.memoryUsage.rss()
|
|
177
|
-
mem_count
|
|
211
|
+
mem_count++
|
|
178
212
|
} else {
|
|
179
213
|
this.rundata.mem = process.memoryUsage()
|
|
180
214
|
mem_count = 0
|
|
@@ -182,16 +216,17 @@ class Monitor {
|
|
|
182
216
|
|
|
183
217
|
this.rundata.mem.total = this.rundata.mem.rss + this.rundata.mem.external
|
|
184
218
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
err
|
|
194
|
-
//
|
|
219
|
+
const msg = this.ipcMsgCache
|
|
220
|
+
msg.pid = process.pid
|
|
221
|
+
msg.cpu = this.rundata.cpuTime
|
|
222
|
+
msg.cputm = diffUs
|
|
223
|
+
msg.mem = this.rundata.mem
|
|
224
|
+
msg.conn = this.rundata.conn
|
|
225
|
+
|
|
226
|
+
process.send(msg, err => {
|
|
227
|
+
if (err) this.config.errorHandle(err, '--ERR-WORKER-SEND--')
|
|
228
|
+
// 忽略管道关闭错误
|
|
229
|
+
//if (err && err.code !== 'ERR_IPC_CHANNEL_CLOSED') {}
|
|
195
230
|
})
|
|
196
231
|
|
|
197
232
|
this.rundata.cpuLast = process.cpuUsage()
|
|
@@ -201,7 +236,7 @@ class Monitor {
|
|
|
201
236
|
}
|
|
202
237
|
|
|
203
238
|
showLoadInfo(w, id) {
|
|
204
|
-
if (this.config.loadInfoType
|
|
239
|
+
if (!this.config.loadInfoType || this.config.loadInfoType === 'null') {
|
|
205
240
|
return
|
|
206
241
|
}
|
|
207
242
|
|
|
@@ -225,31 +260,30 @@ class Monitor {
|
|
|
225
260
|
|
|
226
261
|
this.loadCount += 1;
|
|
227
262
|
if (this.loadCount < this.workerCount.cur) {
|
|
228
|
-
return
|
|
263
|
+
return
|
|
229
264
|
}
|
|
230
265
|
|
|
231
|
-
let
|
|
266
|
+
let load_info = this.fmtLoadInfo(this.config.loadInfoType);
|
|
232
267
|
|
|
233
268
|
if (this.config.loadInfoFile === '--mem') {
|
|
234
|
-
this.loadCache =
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
269
|
+
this.loadCache = load_info;
|
|
270
|
+
} else if (this.loadfd !== null) {
|
|
271
|
+
fs.write(this.loadfd, this.isLoadObj ? JSON.stringify(load_info) : load_info, 0,
|
|
272
|
+
(err, bytes, data) => {
|
|
273
|
+
if (err && this.config.debug) this.config.errorHandle(err, '--ERR-WRITE-FILE--');
|
|
274
|
+
|
|
275
|
+
if (!err) {
|
|
276
|
+
fs.ftruncate(this.loadfd, bytes, e => {});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
);
|
|
245
280
|
} else if (process.ppid > 1 && !this.config.daemon && !this.config.loadInfoFile) {
|
|
246
281
|
console.clear();
|
|
247
282
|
//只有没有开启守护进程才会输出到屏幕
|
|
248
|
-
console.log(
|
|
283
|
+
console.log(load_info);
|
|
249
284
|
}
|
|
250
285
|
|
|
251
286
|
this.loadCount = 0;
|
|
252
|
-
|
|
253
287
|
}
|
|
254
288
|
|
|
255
289
|
checkMem(w, msg) {
|
|
@@ -292,26 +326,16 @@ class Monitor {
|
|
|
292
326
|
let p = null;
|
|
293
327
|
|
|
294
328
|
for (let id in this.workers) {
|
|
295
|
-
|
|
296
329
|
p = this.workers[id];
|
|
297
|
-
|
|
298
330
|
tmp = [(`${p.pid}`).padEnd(9, ' ')];
|
|
299
|
-
|
|
300
331
|
t = p.cpu.user + p.cpu.system;
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
(p.mem.heapTotal / 1048576).toFixed(1).padEnd(8, ' '),
|
|
309
|
-
|
|
310
|
-
(p.mem.heapUsed / 1048576).toFixed(1).padEnd(8, ' '),
|
|
311
|
-
|
|
312
|
-
(p.mem.external / 1048576).toFixed(1).padEnd(9, ' '),
|
|
313
|
-
|
|
314
|
-
(p.mem.total / 1048576).toFixed(1)
|
|
332
|
+
tmp.push((( t * 100 / p.cputm ).toFixed(2) + '%').padEnd(8, ' '),
|
|
333
|
+
(`${p.conn}`).padEnd(8, ' '),
|
|
334
|
+
(p.mem.rss / 1048576).toFixed(1).padEnd(8, ' '),
|
|
335
|
+
(p.mem.heapTotal / 1048576).toFixed(1).padEnd(8, ' '),
|
|
336
|
+
(p.mem.heapUsed / 1048576).toFixed(1).padEnd(8, ' '),
|
|
337
|
+
(p.mem.external / 1048576).toFixed(1).padEnd(9, ' '),
|
|
338
|
+
(p.mem.total / 1048576).toFixed(1)
|
|
315
339
|
);
|
|
316
340
|
|
|
317
341
|
cols.push(tmp.join(''));
|
|
@@ -323,56 +347,44 @@ class Monitor {
|
|
|
323
347
|
+`HTTPS: ${this.config.https ? 'true' : 'false'}; HTTP/2: ${this.config.http2 ? 'true' : 'false'}\n`;
|
|
324
348
|
}
|
|
325
349
|
|
|
326
|
-
if (type === '
|
|
327
|
-
let
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
'15m' : oavg[2].toFixed(2)
|
|
334
|
-
},
|
|
335
|
-
https: this.config.https,
|
|
336
|
-
http2: this.config.http2,
|
|
337
|
-
workers : []
|
|
338
|
-
};
|
|
350
|
+
if (type === 'obj') {
|
|
351
|
+
let lj = this.loadjson
|
|
352
|
+
lj.CPULoadavg['1m'] = oavg[0].toFixed(2)
|
|
353
|
+
lj.CPULoadavg['5m'] = oavg[1].toFixed(2)
|
|
354
|
+
lj.CPULoadavg['15m'] = oavg[2].toFixed(2)
|
|
355
|
+
lj.workers = []
|
|
356
|
+
|
|
339
357
|
for (let id in this.workers) {
|
|
340
358
|
p = this.workers[id];
|
|
341
359
|
|
|
342
|
-
|
|
343
|
-
pid
|
|
344
|
-
cpu
|
|
345
|
-
cputm
|
|
346
|
-
mem
|
|
360
|
+
lj.workers.push({
|
|
361
|
+
pid: p.pid,
|
|
362
|
+
cpu: `${((p.cpu.user + p.cpu.system) * 100 / p.cputm).toFixed(2)}%`,
|
|
363
|
+
cputm: p.cputm,
|
|
364
|
+
mem: {
|
|
347
365
|
rss : (p.mem.rss / 1048576).toFixed(1),
|
|
348
366
|
heap : (p.mem.heapTotal / 1048576).toFixed(1),
|
|
349
367
|
heapused : (p.mem.heapUsed / 1048576).toFixed(1),
|
|
350
368
|
external : (p.mem.external / 1048576).toFixed(1),
|
|
351
369
|
},
|
|
352
370
|
conn : p.conn
|
|
353
|
-
})
|
|
371
|
+
})
|
|
354
372
|
}
|
|
355
|
-
|
|
373
|
+
|
|
374
|
+
return lj
|
|
356
375
|
}
|
|
357
376
|
|
|
358
|
-
if (type === '
|
|
359
|
-
let
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
},
|
|
367
|
-
https: this.config.https,
|
|
368
|
-
http2: this.config.http2,
|
|
369
|
-
workers : this.workers
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
return JSON.stringify(loadjson);
|
|
377
|
+
if (type === 'orgobj') {
|
|
378
|
+
let lj = this.loadjson
|
|
379
|
+
lj.CPULoadavg['1m'] = oavg[0].toFixed(2)
|
|
380
|
+
lj.CPULoadavg['5m'] = oavg[1].toFixed(2)
|
|
381
|
+
lj.CPULoadavg['15m'] = oavg[2].toFixed(2)
|
|
382
|
+
lj.workers = this.workers
|
|
383
|
+
|
|
384
|
+
return lj
|
|
373
385
|
}
|
|
374
386
|
|
|
375
|
-
return
|
|
387
|
+
return null
|
|
376
388
|
}
|
|
377
389
|
|
|
378
390
|
}
|