@nxtedition/lib 13.0.9 → 13.1.0

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.
Files changed (2) hide show
  1. package/app.js +203 -153
  2. package/package.json +1 -1
package/app.js CHANGED
@@ -331,6 +331,74 @@ module.exports = function (appConfig, onTerminate) {
331
331
 
332
332
  const monitorProviders = {}
333
333
 
334
+ let stats$
335
+ if (appConfig.stats) {
336
+ const v8 = require('v8')
337
+ const rxjs = require('rxjs')
338
+ const rx = require('rxjs/operators')
339
+ const { eventLoopUtilization } = require('perf_hooks').performance
340
+
341
+ if (typeof appConfig.stats.subscribe === 'function') {
342
+ stats$ = appConfig.stats
343
+ } else if (typeof appConfig.stats === 'function') {
344
+ stats$ = rxjs.timer(0, 10e3).pipe(
345
+ rx.exhaustMap(() => {
346
+ const ret = appConfig.stats({ ds, couch, logger })
347
+ return ret?.then || ret?.subscribe ? ret : rxjs.of(ret)
348
+ })
349
+ )
350
+ } else if (typeof appConfig.stats === 'object') {
351
+ stats$ = rxjs.timer(0, 10e3).pipe(rx.map(() => appConfig.stats))
352
+ } else {
353
+ stats$ = rxjs.timer(0, 10e3).pipe(rx.map(() => ({})))
354
+ }
355
+
356
+ stats$ = stats$.pipe(
357
+ rx.map((x) => ({
358
+ ...x,
359
+ timestamp: Date.now(),
360
+ })),
361
+ rx.auditTime(1e3),
362
+ rx.filter(Boolean),
363
+ rx.retryWhen((err$) =>
364
+ err$.pipe(
365
+ rx.tap((err) => logger.error({ err }, 'monitor.stats')),
366
+ rx.delay(10e3)
367
+ )
368
+ ),
369
+ rx.startWith({}),
370
+ rx.publishReplay(1),
371
+ rx.refCount()
372
+ )
373
+
374
+ monitorProviders.stats$ = stats$
375
+
376
+ let elu1 = eventLoopUtilization?.()
377
+ const subscription = stats$.pipe(rx.auditTime(10e3)).subscribe((stats) => {
378
+ if (process.env.NODE_ENV === 'production') {
379
+ const elu2 = eventLoopUtilization?.()
380
+ logger.debug(
381
+ {
382
+ ds: ds?.stats,
383
+ couch: couch?.stats,
384
+ lag: toobusy?.lag(),
385
+ memory: process.memoryUsage(),
386
+ utilization: eventLoopUtilization?.(elu2, elu1),
387
+ heap: v8.getHeapStatistics(),
388
+ ...stats,
389
+ },
390
+ 'STATS'
391
+ )
392
+ elu1 = elu2
393
+ }
394
+ })
395
+
396
+ destroyers.push(() => {
397
+ subscription.unsubscribe()
398
+ })
399
+ }
400
+
401
+ let status$
334
402
  if (appConfig.status) {
335
403
  const rxjs = require('rxjs')
336
404
  const rx = require('rxjs/operators')
@@ -338,7 +406,6 @@ module.exports = function (appConfig, onTerminate) {
338
406
  const fp = require('lodash/fp')
339
407
  const hashString = require('./hash')
340
408
 
341
- let status$
342
409
  if (appConfig.status.subscribe) {
343
410
  status$ = appConfig.status
344
411
  } else if (typeof appConfig.status === 'function') {
@@ -358,103 +425,108 @@ module.exports = function (appConfig, onTerminate) {
358
425
  }
359
426
 
360
427
  status$ = rxjs
361
- .combineLatest([
362
- status$.pipe(
363
- rx.filter(Boolean),
364
- rx.catchError((err) => {
365
- logger.error({ err }, 'monitor.status')
366
- return rxjs.of([
367
- {
368
- id: 'app:user_monitor_status',
369
- level: 50,
370
- code: err.code,
371
- msg: err.message,
372
- },
373
- ])
374
- }),
375
- rx.startWith([]),
376
- rx.distinctUntilChanged(fp.isEqual),
377
- rx.repeatWhen((complete$) => complete$.pipe(rx.delay(10e3)))
378
- ),
379
- toobusy
380
- ? rxjs.timer(0, 1e3).pipe(
381
- rx.map(() =>
382
- toobusy.lag() > 1e3
383
- ? [
428
+ .combineLatest(
429
+ [
430
+ status$.pipe(
431
+ rx.filter(Boolean),
432
+ rx.catchError((err) => {
433
+ logger.error({ err }, 'monitor.status')
434
+ return rxjs.of([
435
+ {
436
+ id: 'app:user_monitor_status',
437
+ level: 50,
438
+ code: err.code,
439
+ msg: err.message,
440
+ },
441
+ ])
442
+ }),
443
+ rx.startWith([]),
444
+ rx.distinctUntilChanged(fp.isEqual),
445
+ rx.repeatWhen((complete$) => complete$.pipe(rx.delay(10e3)))
446
+ ),
447
+ toobusy
448
+ ? rxjs.timer(0, 1e3).pipe(
449
+ rx.map(() =>
450
+ toobusy.lag() > 1e3
451
+ ? [
452
+ {
453
+ id: 'app:toobusy_lag',
454
+ level: 40,
455
+ code: 'NXT_LAG',
456
+ msg: `lag: ${toobusy.lag()}`,
457
+ },
458
+ ]
459
+ : []
460
+ ),
461
+ rx.startWith([]),
462
+ rx.distinctUntilChanged(fp.isEqual)
463
+ )
464
+ : rxjs.of({}),
465
+ couch
466
+ ? rxjs.timer(0, 10e3).pipe(
467
+ rx.exhaustMap(async () => {
468
+ try {
469
+ await couch.info()
470
+ } catch (err) {
471
+ return [
384
472
  {
385
- id: 'app:toobusy_lag',
473
+ id: 'app:couch',
386
474
  level: 40,
387
- code: 'NXT_LAG',
388
- msg: `lag: ${toobusy.lag()}`,
475
+ code: err.code,
476
+ msg: 'couch: ' + err.message,
389
477
  },
390
478
  ]
391
- : []
392
- ),
393
- rx.startWith([]),
394
- rx.distinctUntilChanged(fp.isEqual)
395
- )
396
- : rxjs.of({}),
397
- couch
398
- ? rxjs.timer(0, 10e3).pipe(
399
- rx.exhaustMap(async () => {
400
- try {
401
- await couch.info()
402
- } catch (err) {
403
- return [
404
- {
405
- id: 'app:couch',
406
- level: 40,
407
- code: err.code,
408
- msg: 'couch: ' + err.message,
409
- },
410
- ]
411
- }
412
- }),
413
- rx.startWith([]),
414
- rx.distinctUntilChanged(fp.isEqual)
415
- )
416
- : rxjs.of({}),
417
- ds
418
- ? new rxjs.Observable((o) => {
419
- const client = new undici.Client(`http://${new URL(ds._url || ds.url).host}`, {
420
- keepAliveTimeout: 30e3,
421
- })
422
-
423
- const subscription = rxjs
424
- .timer(0, 10e3)
425
- .pipe(
426
- rx.exhaustMap(async () => {
427
- try {
428
- const { body } = await client.request({ method: 'GET', path: '/healthcheck' })
429
- await body.dump()
430
- } catch {
479
+ }
480
+ }),
481
+ rx.startWith([]),
482
+ rx.distinctUntilChanged(fp.isEqual)
483
+ )
484
+ : rxjs.of({}),
485
+ ds
486
+ ? new rxjs.Observable((o) => {
487
+ const client = new undici.Client(`http://${new URL(ds._url || ds.url).host}`, {
488
+ keepAliveTimeout: 30e3,
489
+ })
490
+
491
+ const subscription = rxjs
492
+ .timer(0, 10e3)
493
+ .pipe(
494
+ rx.exhaustMap(async () => {
431
495
  try {
432
496
  const { body } = await client.request({
433
497
  method: 'GET',
434
498
  path: '/healthcheck',
435
499
  })
436
500
  await body.dump()
437
- } catch (err) {
438
- return {
439
- id: 'app:ds_http_connection',
440
- level: 40,
441
- code: err.code,
442
- msg: 'ds: ' + err.message,
501
+ } catch {
502
+ try {
503
+ const { body } = await client.request({
504
+ method: 'GET',
505
+ path: '/healthcheck',
506
+ })
507
+ await body.dump()
508
+ } catch (err) {
509
+ return {
510
+ id: 'app:ds_http_connection',
511
+ level: 40,
512
+ code: err.code,
513
+ msg: 'ds: ' + err.message,
514
+ }
443
515
  }
444
516
  }
445
- }
446
- })
447
- )
448
- .subscribe(o)
449
-
450
- return () => {
451
- client.destroy()
452
- subscription.unsubscribe()
453
- }
454
- }).pipe(rx.startWith([]), rx.distinctUntilChanged(fp.isEqual))
455
- : rxjs.of({}),
456
- rxjs.timer(0, 10e3),
457
- ])
517
+ })
518
+ )
519
+ .subscribe(o)
520
+
521
+ return () => {
522
+ client.destroy()
523
+ subscription.unsubscribe()
524
+ }
525
+ }).pipe(rx.startWith([]), rx.distinctUntilChanged(fp.isEqual))
526
+ : rxjs.of({}),
527
+ rxjs.timer(0, 10e3),
528
+ ].filter(Boolean)
529
+ )
458
530
  .pipe(
459
531
  rx.auditTime(1e3),
460
532
  rx.map(([status, lag, couch, ds]) => {
@@ -490,6 +562,51 @@ module.exports = function (appConfig, onTerminate) {
490
562
  }
491
563
  )
492
564
 
565
+ if (ds && ds.stats.record.records > 100e3) {
566
+ messages.push({
567
+ id: 'app:ds',
568
+ level: 40,
569
+ code: 'NXT_DS_RECORDS',
570
+ msg: 'ds: ' + ds.stats.record.records + ' records',
571
+ })
572
+ }
573
+
574
+ if (ds && ds.stats.record.pruning > 100e3) {
575
+ messages.push({
576
+ id: 'app:ds',
577
+ level: 40,
578
+ code: 'NXT_DS_PRUNING',
579
+ msg: 'ds: ' + ds.stats.record.pruning + ' pruning',
580
+ })
581
+ }
582
+
583
+ if (ds && ds.stats.record.pending > 10e3) {
584
+ messages.push({
585
+ id: 'app:ds',
586
+ level: 40,
587
+ code: 'NXT_DS_PENDING',
588
+ msg: 'ds: ' + ds.stats.record.pending + ' pending',
589
+ })
590
+ }
591
+
592
+ if (ds && ds.stats.record.updating > 10e3) {
593
+ messages.push({
594
+ id: 'app:ds',
595
+ level: 40,
596
+ code: 'NXT_DS_UPDATING',
597
+ msg: 'ds: ' + ds.stats.record.updating + ' updating',
598
+ })
599
+ }
600
+
601
+ if (ds && ds.stats.record.patching > 10e3) {
602
+ messages.push({
603
+ id: 'app:ds',
604
+ level: 40,
605
+ code: 'NXT_DS_PATCHING',
606
+ msg: 'ds: ' + ds.stats.record.patching + ' patching',
607
+ })
608
+ }
609
+
493
610
  return { ...status, messages, timestamp: Date.now() }
494
611
  }),
495
612
  rx.catchError((err) => {
@@ -527,73 +644,6 @@ module.exports = function (appConfig, onTerminate) {
527
644
  })
528
645
  }
529
646
 
530
- if (appConfig.stats) {
531
- const v8 = require('v8')
532
- const rxjs = require('rxjs')
533
- const rx = require('rxjs/operators')
534
- const { eventLoopUtilization } = require('perf_hooks').performance
535
-
536
- let stats$
537
- if (typeof appConfig.stats.subscribe === 'function') {
538
- stats$ = appConfig.stats
539
- } else if (typeof appConfig.stats === 'function') {
540
- stats$ = rxjs.timer(0, 10e3).pipe(
541
- rx.exhaustMap(() => {
542
- const ret = appConfig.stats({ ds, couch, logger })
543
- return ret?.then || ret?.subscribe ? ret : rxjs.of(ret)
544
- })
545
- )
546
- } else if (typeof appConfig.stats === 'object') {
547
- stats$ = rxjs.timer(0, 10e3).pipe(rx.map(() => appConfig.stats))
548
- } else {
549
- stats$ = rxjs.timer(0, 10e3).pipe(rx.map(() => ({})))
550
- }
551
-
552
- stats$ = stats$.pipe(
553
- rx.map((x) => ({
554
- ...x,
555
- timestamp: Date.now(),
556
- })),
557
- rx.auditTime(1e3),
558
- rx.filter(Boolean),
559
- rx.retryWhen((err$) =>
560
- err$.pipe(
561
- rx.tap((err) => logger.error({ err }, 'monitor.stats')),
562
- rx.delay(10e3)
563
- )
564
- ),
565
- rx.startWith({}),
566
- rx.publishReplay(1),
567
- rx.refCount()
568
- )
569
-
570
- monitorProviders.stats$ = stats$
571
-
572
- let elu1 = eventLoopUtilization?.()
573
- const subscription = stats$.pipe(rx.auditTime(10e3)).subscribe((stats) => {
574
- if (process.env.NODE_ENV === 'production') {
575
- const elu2 = eventLoopUtilization?.()
576
- logger.debug(
577
- {
578
- ds: ds?.stats,
579
- couch: couch?.stats,
580
- lag: toobusy?.lag(),
581
- memory: process.memoryUsage(),
582
- utilization: eventLoopUtilization?.(elu2, elu1),
583
- heap: v8.getHeapStatistics(),
584
- ...stats,
585
- },
586
- 'STATS'
587
- )
588
- elu1 = elu2
589
- }
590
- })
591
-
592
- destroyers.push(() => {
593
- subscription.unsubscribe()
594
- })
595
- }
596
-
597
647
  if (ds && Object.keys(monitorProviders).length && appConfig.monitor !== false) {
598
648
  const { isMainThread } = require('node:worker_threads')
599
649
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "13.0.9",
3
+ "version": "13.1.0",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "files": [