@nxtedition/lib 13.0.9 → 13.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.
Files changed (2) hide show
  1. package/app.js +207 -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,157 @@ 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 () => {
495
+ const messages = []
496
+
497
+ if (ds.stats.record.records > 100e3) {
498
+ messages.push({
499
+ id: 'app:ds_record_records',
500
+ level: 40,
501
+ code: 'NXT_DEEPSTREAM_RECORDS_RECORDS',
502
+ msg: 'ds: ' + ds.stats.record.records + ' records',
503
+ })
504
+ }
505
+
506
+ if (ds.stats.record.pruning > 100e3) {
507
+ messages.push({
508
+ id: 'app:ds_record_pruning',
509
+ level: 40,
510
+ code: 'NXT_DEEPSTREAM_RECORDS_PRUNING',
511
+ msg: 'ds: ' + ds.stats.record.pruning + ' pruning',
512
+ })
513
+ }
514
+
515
+ if (ds.stats.record.pending > 10e3) {
516
+ messages.push({
517
+ id: 'app:ds_record_pending',
518
+ level: 40,
519
+ code: 'NXT_DEEPSTREAM_RECORDS_PENDING',
520
+ msg: 'ds: ' + ds.stats.record.pending + ' pending',
521
+ })
522
+ }
523
+
524
+ if (ds.stats.record.updating > 10e3) {
525
+ messages.push({
526
+ id: 'app:ds_record_updating',
527
+ level: 40,
528
+ code: 'NXT_DEEPSTREAM_RECORDS_UPDATING',
529
+ msg: 'ds: ' + ds.stats.record.updating + ' updating',
530
+ })
531
+ }
532
+
533
+ if (ds.stats.record.patching > 10e3) {
534
+ messages.push({
535
+ id: 'app:ds_record_patching',
536
+ level: 40,
537
+ code: 'NXT_DEEPSTREAM_RECORDS_PATCHING',
538
+ msg: 'ds: ' + ds.stats.record.patching + ' patching',
539
+ })
540
+ }
541
+
431
542
  try {
432
543
  const { body } = await client.request({
433
544
  method: 'GET',
434
545
  path: '/healthcheck',
435
546
  })
436
547
  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,
548
+ } catch {
549
+ try {
550
+ const { body } = await client.request({
551
+ method: 'GET',
552
+ path: '/healthcheck',
553
+ })
554
+ await body.dump()
555
+ } catch (err) {
556
+ messages.push({
557
+ id: 'app:ds_http_connection',
558
+ level: 40,
559
+ code: err.code,
560
+ msg: 'ds: ' + err.message,
561
+ })
443
562
  }
444
563
  }
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
- ])
564
+
565
+ return messages
566
+ })
567
+ )
568
+ .subscribe(o)
569
+
570
+ return () => {
571
+ client.destroy()
572
+ subscription.unsubscribe()
573
+ }
574
+ }).pipe(rx.startWith([]), rx.distinctUntilChanged(fp.isEqual))
575
+ : rxjs.of({}),
576
+ rxjs.timer(0, 10e3),
577
+ ].filter(Boolean)
578
+ )
458
579
  .pipe(
459
580
  rx.auditTime(1e3),
460
581
  rx.map(([status, lag, couch, ds]) => {
@@ -527,73 +648,6 @@ module.exports = function (appConfig, onTerminate) {
527
648
  })
528
649
  }
529
650
 
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
651
  if (ds && Object.keys(monitorProviders).length && appConfig.monitor !== false) {
598
652
  const { isMainThread } = require('node:worker_threads')
599
653
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "13.0.9",
3
+ "version": "13.1.1",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "files": [