@nxtedition/lib 28.0.11 → 28.0.13
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/app.js +322 -307
- package/package.json +3 -3
package/app.js
CHANGED
|
@@ -30,7 +30,6 @@ import { makeCouch } from './couch.js'
|
|
|
30
30
|
import { makeTemplateCompiler } from '@nxtedition/template'
|
|
31
31
|
import { makeDeepstream } from './deepstream.js'
|
|
32
32
|
import * as rxjs from 'rxjs'
|
|
33
|
-
import rx from 'rxjs/operators'
|
|
34
33
|
import hashString from './hash.js'
|
|
35
34
|
import { makeTrace } from './trace.js'
|
|
36
35
|
import { compose, createServer } from './http.js'
|
|
@@ -615,40 +614,40 @@ export function makeApp(appConfig, onTerminateOrMeta, metaOrNull) {
|
|
|
615
614
|
compiler = makeTemplateCompiler({ ds, logger, ...appConfig.compiler })
|
|
616
615
|
}
|
|
617
616
|
|
|
618
|
-
const monitorProviders = {
|
|
617
|
+
const monitorProviders = {
|
|
618
|
+
stats$: new rxjs.BehaviorSubject({}),
|
|
619
|
+
status$: new rxjs.BehaviorSubject({ messages: [] }),
|
|
620
|
+
}
|
|
619
621
|
|
|
620
|
-
let stats$
|
|
621
622
|
if (appConfig.stats) {
|
|
623
|
+
let stats$
|
|
624
|
+
|
|
622
625
|
if (typeof appConfig.stats.subscribe === 'function') {
|
|
623
626
|
stats$ = appConfig.stats
|
|
624
627
|
} else if (typeof appConfig.stats === 'function') {
|
|
625
628
|
stats$ = rxjs.timer(0, 10e3).pipe(
|
|
626
|
-
|
|
629
|
+
rxjs.exhaustMap(() => {
|
|
627
630
|
const ret = appConfig.stats({ ds, couch, logger })
|
|
628
631
|
return ret?.then || ret?.subscribe ? ret : rxjs.of(ret)
|
|
629
632
|
}),
|
|
630
633
|
)
|
|
631
634
|
} else if (typeof appConfig.stats === 'object') {
|
|
632
|
-
stats$ = rxjs.timer(0, 10e3).pipe(
|
|
635
|
+
stats$ = rxjs.timer(0, 10e3).pipe(rxjs.map(() => appConfig.stats))
|
|
633
636
|
} else {
|
|
634
|
-
stats$ = rxjs.timer(0, 10e3).pipe(
|
|
637
|
+
stats$ = rxjs.timer(0, 10e3).pipe(rxjs.map(() => ({})))
|
|
635
638
|
}
|
|
636
639
|
|
|
637
640
|
let statsMap
|
|
638
641
|
|
|
639
642
|
const startTime = Date.now()
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
rxjs.timer(0, 1e3).pipe(
|
|
649
|
-
rx.map(() => performance.eventLoopUtilization?.()),
|
|
650
|
-
rx.pairwise(),
|
|
651
|
-
rx.map(([elu1, elu2]) => {
|
|
643
|
+
|
|
644
|
+
appDestroyers.unshift(
|
|
645
|
+
rxjs
|
|
646
|
+
.timer(0, 1e3)
|
|
647
|
+
.pipe(
|
|
648
|
+
rxjs.map(() => performance.eventLoopUtilization?.()),
|
|
649
|
+
rxjs.pairwise(),
|
|
650
|
+
rxjs.map(([elu1, elu2]) => {
|
|
652
651
|
const mem = process.memoryUsage()
|
|
653
652
|
const cpu = process.cpuUsage()
|
|
654
653
|
|
|
@@ -660,24 +659,27 @@ export function makeApp(appConfig, onTerminateOrMeta, metaOrNull) {
|
|
|
660
659
|
arrayBuffers: mem.arrayBuffers,
|
|
661
660
|
containerLimit: getContainerMemoryLimit(),
|
|
662
661
|
containerUsage: getContainerMemoryUsage(),
|
|
663
|
-
totalHeapTotal: 0,
|
|
664
|
-
totalHeapUsed: 0,
|
|
665
|
-
totalExternal: 0,
|
|
666
|
-
totalArrayBuffers: 0,
|
|
667
662
|
}
|
|
668
663
|
|
|
669
664
|
const http = {
|
|
670
665
|
userAgent,
|
|
671
666
|
pending: globalThis._nxt_lib_http_pending?.size,
|
|
672
|
-
totalPending: 0,
|
|
673
667
|
}
|
|
674
668
|
|
|
675
669
|
const undici = {
|
|
676
670
|
sockets: globalThis.__undici_sockets?.size ?? 0,
|
|
677
|
-
totalSockets: 0,
|
|
678
671
|
}
|
|
679
672
|
|
|
680
673
|
if (statsMap) {
|
|
674
|
+
memory.totalHeapTotal = 0
|
|
675
|
+
memory.totalHeapUsed = 0
|
|
676
|
+
memory.totalExternal = 0
|
|
677
|
+
memory.totalArrayBuffers = 0
|
|
678
|
+
|
|
679
|
+
http.totalPending = 0
|
|
680
|
+
|
|
681
|
+
undici.totalSockets = 0
|
|
682
|
+
|
|
681
683
|
for (const stats of statsMap.values()) {
|
|
682
684
|
memory.totalHeapTotal += stats.memory?.heapTotal ?? 0
|
|
683
685
|
memory.totalHeapUsed += stats.memory?.heapUsed ?? 0
|
|
@@ -690,7 +692,10 @@ export function makeApp(appConfig, onTerminateOrMeta, metaOrNull) {
|
|
|
690
692
|
}
|
|
691
693
|
}
|
|
692
694
|
|
|
695
|
+
const now = Date.now()
|
|
693
696
|
return {
|
|
697
|
+
uptime: now - startTime,
|
|
698
|
+
timestamp: now,
|
|
694
699
|
ds: ds?.stats,
|
|
695
700
|
couch: couch?.stats,
|
|
696
701
|
lag: toobusy?.lag(),
|
|
@@ -706,45 +711,56 @@ export function makeApp(appConfig, onTerminateOrMeta, metaOrNull) {
|
|
|
706
711
|
undici,
|
|
707
712
|
}
|
|
708
713
|
}),
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
rx.refCount(),
|
|
714
|
+
rxjs.withLatestFrom(stats$.pipe(rxjs.startWith({}))),
|
|
715
|
+
rxjs.map(([appStats, serviceStats]) => ({
|
|
716
|
+
...appStats,
|
|
717
|
+
// TODO (fix): [serviceName] is not great and can collide.
|
|
718
|
+
[serviceName]: serviceStats,
|
|
719
|
+
})),
|
|
720
|
+
rxjs.retry({
|
|
721
|
+
delay(err, retryCount) {
|
|
722
|
+
logger.error({ err, retryCount }, 'monitor.stats$ failed')
|
|
723
|
+
return rxjs.timer(10e3)
|
|
724
|
+
},
|
|
725
|
+
}),
|
|
726
|
+
)
|
|
727
|
+
.subscribe(monitorProviders.stats$),
|
|
724
728
|
)
|
|
725
729
|
|
|
726
730
|
const statsBC = new BroadcastChannel('nxt:app:stats').unref()
|
|
731
|
+
|
|
727
732
|
if (isMainThread) {
|
|
728
733
|
statsMap = new Map()
|
|
729
734
|
statsBC.onmessage = ({ data: { data, id } }) => {
|
|
730
|
-
|
|
735
|
+
if (data != null) {
|
|
736
|
+
statsMap.set(id, data)
|
|
737
|
+
} else {
|
|
738
|
+
statsMap.delete(id)
|
|
739
|
+
}
|
|
731
740
|
}
|
|
732
741
|
}
|
|
733
742
|
|
|
734
|
-
|
|
743
|
+
appDestroyers.unshift(
|
|
744
|
+
monitorProviders.stats$
|
|
745
|
+
.subscribe((stats) => {
|
|
746
|
+
statsBC.postMessage({ id: threadId, data: stats })
|
|
747
|
+
})
|
|
748
|
+
.add(() => {
|
|
749
|
+
statsBC.postMessage({ id: threadId, data: undefined })
|
|
750
|
+
}),
|
|
751
|
+
)
|
|
735
752
|
|
|
736
753
|
if (process.env.NODE_ENV === 'production') {
|
|
737
754
|
appDestroyers.unshift(
|
|
738
|
-
stats$.pipe(
|
|
739
|
-
statsBC.postMessage({ id: threadId, data: stats })
|
|
755
|
+
monitorProviders.stats$.pipe(rxjs.auditTime(10e3)).subscribe((stats) => {
|
|
740
756
|
logger.debug(stats, 'STATS')
|
|
741
757
|
}),
|
|
742
758
|
)
|
|
743
759
|
}
|
|
744
760
|
}
|
|
745
761
|
|
|
746
|
-
let status$
|
|
747
762
|
if (appConfig.status) {
|
|
763
|
+
let status$
|
|
748
764
|
if (appConfig.status.subscribe) {
|
|
749
765
|
status$ = appConfig.status
|
|
750
766
|
} else if (typeof appConfig.status === 'function') {
|
|
@@ -754,294 +770,293 @@ export function makeApp(appConfig, onTerminateOrMeta, metaOrNull) {
|
|
|
754
770
|
return ret?.then || ret?.subscribe ? ret : rxjs.of(ret)
|
|
755
771
|
})
|
|
756
772
|
.pipe(
|
|
757
|
-
|
|
758
|
-
|
|
773
|
+
rxjs.catchError((err) => rxjs.of({ warnings: [err.message] })),
|
|
774
|
+
rxjs.repeatWhen(() => rxjs.timer(10e3)),
|
|
759
775
|
)
|
|
760
776
|
} else if (appConfig.status && typeof appConfig.status === 'object') {
|
|
761
|
-
status$ = rxjs.timer(0, 10e3).pipe(
|
|
777
|
+
status$ = rxjs.timer(0, 10e3).pipe(rxjs.exhaustMap(() => appConfig.status))
|
|
762
778
|
} else {
|
|
763
779
|
status$ = rxjs.of({})
|
|
764
780
|
}
|
|
765
781
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
stats$.pipe(
|
|
788
|
-
rx.map(({ memory, heap, utilization, undici, http }) => {
|
|
789
|
-
const messages = []
|
|
790
|
-
|
|
791
|
-
if (memory?.containerLimit) {
|
|
792
|
-
const usagePercent = (memory.containerUsage / memory.containerLimit) * 100
|
|
793
|
-
messages.push({
|
|
794
|
-
id: 'app:container_memory_usage',
|
|
795
|
-
level: usagePercent > 90 ? 50 : usagePercent > 70 ? 40 : 30,
|
|
796
|
-
msg: `Memory Usage: ${usagePercent.toFixed(2)}%`,
|
|
797
|
-
})
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
if (heap) {
|
|
801
|
-
const usagePercent = (heap.used_heap_size / heap.heap_size_limit) * 100
|
|
802
|
-
messages.push({
|
|
803
|
-
id: 'app:heap_memory_usage',
|
|
804
|
-
level: usagePercent > 90 ? 50 : usagePercent > 70 ? 40 : 30,
|
|
805
|
-
msg: `Heap Usage: ${usagePercent.toFixed(2)}%`,
|
|
806
|
-
})
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
if (utilization) {
|
|
810
|
-
const elp = utilization.utilization * 100
|
|
811
|
-
messages.push({
|
|
812
|
-
id: 'app:event_loop_utilization',
|
|
813
|
-
level: elp > 95 ? 50 : elp > 80 ? 40 : 30,
|
|
814
|
-
msg: `Event Loop Utilization: ${elp.toFixed(2)}%`,
|
|
815
|
-
})
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
if (undici) {
|
|
819
|
-
messages.push({
|
|
820
|
-
id: 'app:undici_upstream_sockets',
|
|
821
|
-
level: undici.totalSockets > 8192 ? 50 : undici.totalSockets > 4096 ? 40 : 30,
|
|
822
|
-
msg: `Undici: ${undici.totalSockets} upstream connected`,
|
|
823
|
-
})
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
if (http) {
|
|
827
|
-
messages.push({
|
|
828
|
-
id: 'app:http_pending_requests',
|
|
829
|
-
level: http.totalPending > 8192 ? 50 : http.totalPending > 4096 ? 40 : 30,
|
|
830
|
-
msg: `HTTP: ${http.totalPending} pending requests`,
|
|
831
|
-
})
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
return messages
|
|
835
|
-
}),
|
|
836
|
-
),
|
|
837
|
-
toobusy?.appLag$.pipe(
|
|
838
|
-
rx.map((lag) =>
|
|
839
|
-
lag == null
|
|
840
|
-
? []
|
|
841
|
-
: [
|
|
842
|
-
{
|
|
843
|
-
id: 'app:toobusy_lag',
|
|
844
|
-
level: lag > 1e3 ? 50 : lag > toobusy.maxLag ? 40 : 30,
|
|
845
|
-
code: 'NXT_LAG',
|
|
846
|
-
msg: `Lag: ${lag.toFixed(2)} ms`,
|
|
847
|
-
},
|
|
848
|
-
],
|
|
782
|
+
appDestroyers.unshift(
|
|
783
|
+
rxjs
|
|
784
|
+
.combineLatest(
|
|
785
|
+
[
|
|
786
|
+
status$.pipe(
|
|
787
|
+
rxjs.filter(Boolean),
|
|
788
|
+
rxjs.map((xs) => (Array.isArray(xs) ? { messages: xs } : xs)),
|
|
789
|
+
rxjs.catchError((err) => {
|
|
790
|
+
logger.error({ err }, 'monitor.status')
|
|
791
|
+
return rxjs.of([
|
|
792
|
+
{
|
|
793
|
+
id: 'app:user_monitor_status',
|
|
794
|
+
level: 50,
|
|
795
|
+
code: err.code,
|
|
796
|
+
msg: err.message,
|
|
797
|
+
},
|
|
798
|
+
])
|
|
799
|
+
}),
|
|
800
|
+
rxjs.startWith([]),
|
|
801
|
+
rxjs.distinctUntilChanged(fp.isEqual),
|
|
802
|
+
rxjs.repeatWhen((complete$) => complete$.pipe(rxjs.delay(10e3))),
|
|
849
803
|
),
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
804
|
+
monitorProviders.stats$?.pipe(
|
|
805
|
+
rxjs.map(({ memory, heap, utilization, undici, http }) => {
|
|
806
|
+
const messages = []
|
|
807
|
+
|
|
808
|
+
if (memory?.containerLimit) {
|
|
809
|
+
const usagePercent = (memory.containerUsage / memory.containerLimit) * 100
|
|
810
|
+
messages.push({
|
|
811
|
+
id: 'app:container_memory_usage',
|
|
812
|
+
level: usagePercent > 90 ? 50 : usagePercent > 70 ? 40 : 30,
|
|
813
|
+
msg: `Memory Usage: ${usagePercent.toFixed(2)}%`,
|
|
814
|
+
})
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (heap) {
|
|
818
|
+
const usagePercent = (heap.used_heap_size / heap.heap_size_limit) * 100
|
|
819
|
+
messages.push({
|
|
820
|
+
id: 'app:heap_memory_usage',
|
|
821
|
+
level: usagePercent > 90 ? 50 : usagePercent > 70 ? 40 : 30,
|
|
822
|
+
msg: `Heap Usage: ${usagePercent.toFixed(2)}%`,
|
|
823
|
+
})
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if (utilization) {
|
|
827
|
+
const elp = utilization.utilization * 100
|
|
828
|
+
messages.push({
|
|
829
|
+
id: 'app:event_loop_utilization',
|
|
830
|
+
level: elp > 95 ? 50 : elp > 80 ? 40 : 30,
|
|
831
|
+
msg: `Event Loop Utilization: ${elp.toFixed(2)}%`,
|
|
832
|
+
})
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (undici) {
|
|
836
|
+
messages.push({
|
|
837
|
+
id: 'app:undici_upstream_sockets',
|
|
838
|
+
level: undici.totalSockets > 8192 ? 50 : undici.totalSockets > 4096 ? 40 : 30,
|
|
839
|
+
msg: `Undici: ${undici.totalSockets} upstream connected`,
|
|
840
|
+
})
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
if (http) {
|
|
844
|
+
messages.push({
|
|
845
|
+
id: 'app:http_pending_requests',
|
|
846
|
+
level: http.totalPending > 8192 ? 50 : http.totalPending > 4096 ? 40 : 30,
|
|
847
|
+
msg: `HTTP: ${http.totalPending} pending requests`,
|
|
848
|
+
})
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
return messages
|
|
852
|
+
}),
|
|
863
853
|
),
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
await couch.up()
|
|
870
|
-
return [
|
|
854
|
+
toobusy?.appLag$.pipe(
|
|
855
|
+
rxjs.map((lag) =>
|
|
856
|
+
lag == null
|
|
857
|
+
? []
|
|
858
|
+
: [
|
|
871
859
|
{
|
|
872
|
-
id: 'app:
|
|
873
|
-
level: 30,
|
|
874
|
-
|
|
860
|
+
id: 'app:toobusy_lag',
|
|
861
|
+
level: lag > 1e3 ? 50 : lag > toobusy.maxLag ? 40 : 30,
|
|
862
|
+
code: 'NXT_LAG',
|
|
863
|
+
msg: `Lag: ${lag.toFixed(2)} ms`,
|
|
875
864
|
},
|
|
876
|
-
]
|
|
877
|
-
|
|
878
|
-
|
|
865
|
+
],
|
|
866
|
+
),
|
|
867
|
+
) ?? rxjs.of([]),
|
|
868
|
+
underPressure?.pressure$?.pipe(
|
|
869
|
+
rxjs.map((pressure) =>
|
|
870
|
+
pressure == null
|
|
871
|
+
? []
|
|
872
|
+
: [
|
|
879
873
|
{
|
|
880
|
-
id: 'app:
|
|
874
|
+
id: 'app:under_pressure',
|
|
881
875
|
level: 40,
|
|
882
|
-
code:
|
|
883
|
-
msg:
|
|
876
|
+
code: 'NXT_PRESSURE',
|
|
877
|
+
msg: `Under Pressure`,
|
|
884
878
|
},
|
|
885
|
-
]
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
rxjs.map((connectionState) =>
|
|
895
|
-
connectionState === 'OPEN'
|
|
896
|
-
? [
|
|
879
|
+
],
|
|
880
|
+
),
|
|
881
|
+
) ?? rxjs.of([]),
|
|
882
|
+
couch
|
|
883
|
+
? rxjs.timer(0, 10e3).pipe(
|
|
884
|
+
rxjs.exhaustMap(async () => {
|
|
885
|
+
try {
|
|
886
|
+
await couch.up()
|
|
887
|
+
return [
|
|
897
888
|
{
|
|
898
|
-
id: 'app:
|
|
889
|
+
id: 'app:couch',
|
|
899
890
|
level: 30,
|
|
900
|
-
msg: '
|
|
901
|
-
data: { connectionState },
|
|
891
|
+
msg: 'Couch: connected',
|
|
902
892
|
},
|
|
903
893
|
]
|
|
904
|
-
|
|
894
|
+
} catch (err) {
|
|
895
|
+
return [
|
|
905
896
|
{
|
|
906
|
-
id: 'app:
|
|
897
|
+
id: 'app:couch',
|
|
907
898
|
level: 40,
|
|
908
|
-
|
|
909
|
-
|
|
899
|
+
code: err.code,
|
|
900
|
+
msg: 'Couch: ' + err.message,
|
|
910
901
|
},
|
|
911
|
-
]
|
|
912
|
-
|
|
902
|
+
]
|
|
903
|
+
}
|
|
904
|
+
}),
|
|
905
|
+
rxjs.startWith([]),
|
|
906
|
+
rxjs.distinctUntilChanged(fp.isEqual),
|
|
907
|
+
)
|
|
908
|
+
: rxjs.of({}),
|
|
909
|
+
ds
|
|
910
|
+
? rxjs.fromEvent(ds, 'connectionStateChanged').pipe(
|
|
911
|
+
rxjs.map((connectionState) =>
|
|
912
|
+
connectionState === 'OPEN'
|
|
913
|
+
? [
|
|
914
|
+
{
|
|
915
|
+
id: 'app:ds_connection_state',
|
|
916
|
+
level: 30,
|
|
917
|
+
msg: 'Deepstream: connected',
|
|
918
|
+
data: { connectionState },
|
|
919
|
+
},
|
|
920
|
+
]
|
|
921
|
+
: [
|
|
922
|
+
{
|
|
923
|
+
id: 'app:ds_connection_state',
|
|
924
|
+
level: 40,
|
|
925
|
+
msg: 'Deepstream: connecting',
|
|
926
|
+
data: { connectionState },
|
|
927
|
+
},
|
|
928
|
+
],
|
|
929
|
+
),
|
|
930
|
+
)
|
|
931
|
+
: rxjs.of([]),
|
|
932
|
+
ds
|
|
933
|
+
? rxjs.timer(0, 10e3).pipe(
|
|
934
|
+
rxjs.exhaustMap(async () => {
|
|
935
|
+
const messages = []
|
|
936
|
+
|
|
937
|
+
if (ds.stats.record.records > 100e3) {
|
|
938
|
+
messages.push({
|
|
939
|
+
id: 'app:ds_record_records',
|
|
940
|
+
level: 40,
|
|
941
|
+
code: 'NXT_DEEPSTREAM_RECORDS_RECORDS',
|
|
942
|
+
msg: 'Deepstream: ' + ds.stats.record.records + ' records',
|
|
943
|
+
})
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
if (ds.stats.record.pruning > 100e3) {
|
|
947
|
+
messages.push({
|
|
948
|
+
id: 'app:ds_record_pruning',
|
|
949
|
+
level: 40,
|
|
950
|
+
code: 'NXT_DEEPSTREAM_RECORDS_PRUNING',
|
|
951
|
+
msg: 'Deepstream: ' + ds.stats.record.pruning + ' pruning',
|
|
952
|
+
})
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (ds.stats.record.pending > 10e3) {
|
|
956
|
+
messages.push({
|
|
957
|
+
id: 'app:ds_record_pending',
|
|
958
|
+
level: 40,
|
|
959
|
+
code: 'NXT_DEEPSTREAM_RECORDS_PENDING',
|
|
960
|
+
msg: 'Deepstream: ' + ds.stats.record.pending + ' pending',
|
|
961
|
+
})
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
if (ds.stats.record.updating > 10e3) {
|
|
965
|
+
messages.push({
|
|
966
|
+
id: 'app:ds_record_updating',
|
|
967
|
+
level: 40,
|
|
968
|
+
code: 'NXT_DEEPSTREAM_RECORDS_UPDATING',
|
|
969
|
+
msg: 'Deepstream: ' + ds.stats.record.updating + ' updating',
|
|
970
|
+
})
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
if (ds.stats.record.patching > 10e3) {
|
|
974
|
+
messages.push({
|
|
975
|
+
id: 'app:ds_record_patching',
|
|
976
|
+
level: 40,
|
|
977
|
+
code: 'NXT_DEEPSTREAM_RECORDS_PATCHING',
|
|
978
|
+
msg: 'Deepstream: ' + ds.stats.record.patching + ' patching',
|
|
979
|
+
})
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
return messages
|
|
983
|
+
}),
|
|
984
|
+
)
|
|
985
|
+
: rxjs.of([]),
|
|
986
|
+
rxjs.timer(0, 10e3),
|
|
987
|
+
].filter(Boolean),
|
|
988
|
+
)
|
|
989
|
+
.pipe(
|
|
990
|
+
rxjs.auditTime(1e3),
|
|
991
|
+
rxjs.map(([status, lag, couch, ds]) => {
|
|
992
|
+
const messages = [
|
|
993
|
+
lag,
|
|
994
|
+
couch,
|
|
995
|
+
ds,
|
|
996
|
+
[
|
|
997
|
+
status?.messages,
|
|
998
|
+
fp.map((x) => (fp.isString(x) ? { msg: x, level: 40 } : x), status?.warnings),
|
|
999
|
+
status,
|
|
1000
|
+
].find((x) => fp.isArray(x) && !fp.isEmpty(x)) ?? [],
|
|
1001
|
+
]
|
|
1002
|
+
.flat()
|
|
1003
|
+
.filter((x) => fp.isPlainObject(x) && !fp.isEmpty(x))
|
|
1004
|
+
.map((message) =>
|
|
1005
|
+
message.msg || !message.message
|
|
1006
|
+
? message
|
|
1007
|
+
: {
|
|
1008
|
+
...message,
|
|
1009
|
+
message: undefined,
|
|
1010
|
+
msg: message.message,
|
|
1011
|
+
},
|
|
913
1012
|
)
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
level: 40,
|
|
924
|
-
code: 'NXT_DEEPSTREAM_RECORDS_RECORDS',
|
|
925
|
-
msg: 'Deepstream: ' + ds.stats.record.records + ' records',
|
|
926
|
-
})
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
if (ds.stats.record.pruning > 100e3) {
|
|
930
|
-
messages.push({
|
|
931
|
-
id: 'app:ds_record_pruning',
|
|
932
|
-
level: 40,
|
|
933
|
-
code: 'NXT_DEEPSTREAM_RECORDS_PRUNING',
|
|
934
|
-
msg: 'Deepstream: ' + ds.stats.record.pruning + ' pruning',
|
|
935
|
-
})
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
if (ds.stats.record.pending > 10e3) {
|
|
939
|
-
messages.push({
|
|
940
|
-
id: 'app:ds_record_pending',
|
|
941
|
-
level: 40,
|
|
942
|
-
code: 'NXT_DEEPSTREAM_RECORDS_PENDING',
|
|
943
|
-
msg: 'Deepstream: ' + ds.stats.record.pending + ' pending',
|
|
944
|
-
})
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
if (ds.stats.record.updating > 10e3) {
|
|
948
|
-
messages.push({
|
|
949
|
-
id: 'app:ds_record_updating',
|
|
950
|
-
level: 40,
|
|
951
|
-
code: 'NXT_DEEPSTREAM_RECORDS_UPDATING',
|
|
952
|
-
msg: 'Deepstream: ' + ds.stats.record.updating + ' updating',
|
|
953
|
-
})
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
if (ds.stats.record.patching > 10e3) {
|
|
957
|
-
messages.push({
|
|
958
|
-
id: 'app:ds_record_patching',
|
|
959
|
-
level: 40,
|
|
960
|
-
code: 'NXT_DEEPSTREAM_RECORDS_PATCHING',
|
|
961
|
-
msg: 'Deepstream: ' + ds.stats.record.patching + ' patching',
|
|
962
|
-
})
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
return messages
|
|
966
|
-
}),
|
|
1013
|
+
.map((message) =>
|
|
1014
|
+
message.id
|
|
1015
|
+
? message
|
|
1016
|
+
: {
|
|
1017
|
+
...message,
|
|
1018
|
+
id: hashString(
|
|
1019
|
+
[message.msg, message].find(fp.isString) ?? JSON.stringify(message),
|
|
1020
|
+
),
|
|
1021
|
+
},
|
|
967
1022
|
)
|
|
968
|
-
: rxjs.of([]),
|
|
969
|
-
rxjs.timer(0, 10e3),
|
|
970
|
-
].filter(Boolean),
|
|
971
|
-
)
|
|
972
|
-
.pipe(
|
|
973
|
-
rx.auditTime(1e3),
|
|
974
|
-
rx.map(([status, lag, couch, ds]) => {
|
|
975
|
-
const messages = [
|
|
976
|
-
lag,
|
|
977
|
-
couch,
|
|
978
|
-
ds,
|
|
979
|
-
[
|
|
980
|
-
status?.messages,
|
|
981
|
-
fp.map((x) => (fp.isString(x) ? { msg: x, level: 40 } : x), status?.warnings),
|
|
982
|
-
status,
|
|
983
|
-
].find((x) => fp.isArray(x) && !fp.isEmpty(x)) ?? [],
|
|
984
|
-
]
|
|
985
|
-
.flat()
|
|
986
|
-
.filter((x) => fp.isPlainObject(x) && !fp.isEmpty(x))
|
|
987
|
-
.map((message) =>
|
|
988
|
-
message.msg || !message.message
|
|
989
|
-
? message
|
|
990
|
-
: {
|
|
991
|
-
...message,
|
|
992
|
-
message: undefined,
|
|
993
|
-
msg: message.message,
|
|
994
|
-
},
|
|
995
|
-
)
|
|
996
|
-
.map((message) =>
|
|
997
|
-
message.id
|
|
998
|
-
? message
|
|
999
|
-
: {
|
|
1000
|
-
...message,
|
|
1001
|
-
id: hashString(
|
|
1002
|
-
[message.msg, message].find(fp.isString) ?? JSON.stringify(message),
|
|
1003
|
-
),
|
|
1004
|
-
},
|
|
1005
|
-
)
|
|
1006
1023
|
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1024
|
+
return { ...status, messages, timestamp: Date.now() }
|
|
1025
|
+
}),
|
|
1026
|
+
rxjs.catchError((err) => {
|
|
1027
|
+
logger.error({ err }, 'monitor.status')
|
|
1028
|
+
return rxjs.of({
|
|
1029
|
+
messages: [{ id: 'app:monitor_status', level: 50, code: err.code, msg: err.message }],
|
|
1030
|
+
})
|
|
1031
|
+
}),
|
|
1032
|
+
rxjs.repeatWhen((complete$) => complete$.pipe(rxjs.delay(10e3))),
|
|
1033
|
+
rxjs.startWith({}),
|
|
1034
|
+
rxjs.distinctUntilChanged(fp.isEqual),
|
|
1035
|
+
)
|
|
1036
|
+
.subscribe(monitorProviders.status$),
|
|
1037
|
+
)
|
|
1021
1038
|
|
|
1022
|
-
|
|
1023
|
-
.
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1039
|
+
appDestroyers.unshift(
|
|
1040
|
+
monitorProviders.status$
|
|
1041
|
+
.pipe(rxjs.auditTime(1e3), rxjs.pluck('messages'), rxjs.startWith([]), rxjs.pairwise())
|
|
1042
|
+
.subscribe(([prev, next]) => {
|
|
1043
|
+
for (const { level, msg: status, ...message } of fp.differenceBy('id', next, prev)) {
|
|
1044
|
+
if (level >= 50) {
|
|
1045
|
+
logger.error({ ...message, status }, `status added`)
|
|
1046
|
+
} else if (level >= 40) {
|
|
1047
|
+
logger.warn({ ...message, status }, `status added`)
|
|
1048
|
+
} else {
|
|
1049
|
+
logger.info({ ...message, status }, `status added`)
|
|
1050
|
+
}
|
|
1032
1051
|
}
|
|
1033
|
-
}
|
|
1034
1052
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1053
|
+
for (const { level, msg: status, ...message } of fp.differenceBy('id', prev, next)) {
|
|
1054
|
+
if (level >= 40) {
|
|
1055
|
+
logger.info({ ...message, status }, `status removed`)
|
|
1056
|
+
}
|
|
1038
1057
|
}
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
monitorProviders.status$ = status$
|
|
1043
|
-
|
|
1044
|
-
appDestroyers.unshift(loggerSubscription)
|
|
1058
|
+
}),
|
|
1059
|
+
)
|
|
1045
1060
|
}
|
|
1046
1061
|
|
|
1047
1062
|
if (ds && Object.keys(monitorProviders).length && appConfig.monitor !== false) {
|
|
@@ -1275,13 +1290,13 @@ export function makeApp(appConfig, onTerminateOrMeta, metaOrNull) {
|
|
|
1275
1290
|
try {
|
|
1276
1291
|
if (req.method === 'GET' && req.url === '/stats') {
|
|
1277
1292
|
res.setHeader('content-type', 'application/json')
|
|
1278
|
-
res.end(JSON.stringify(stats$.value))
|
|
1293
|
+
res.end(JSON.stringify(monitorProviders.stats$.value))
|
|
1279
1294
|
return
|
|
1280
1295
|
}
|
|
1281
1296
|
|
|
1282
1297
|
if (req.method === 'GET' && req.url === '/status') {
|
|
1283
1298
|
res.setHeader('content-type', 'application/json')
|
|
1284
|
-
res.end(JSON.stringify(status$.value))
|
|
1299
|
+
res.end(JSON.stringify(monitorProviders.status$.value))
|
|
1285
1300
|
return
|
|
1286
1301
|
}
|
|
1287
1302
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxtedition/lib",
|
|
3
|
-
"version": "28.0.
|
|
3
|
+
"version": "28.0.13",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"author": "Robert Nagy <robert.nagy@boffins.se>",
|
|
6
6
|
"type": "module",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@elastic/transport": "^8.9.3",
|
|
53
53
|
"@nxtedition/nxt-undici": "^7.1.9",
|
|
54
54
|
"@nxtedition/sched": "^1.0.2",
|
|
55
|
-
"@nxtedition/template": "^1.0.
|
|
55
|
+
"@nxtedition/template": "^1.0.10",
|
|
56
56
|
"@nxtedition/weak-cache": "^1.0.2",
|
|
57
57
|
"diff": "5.2.0",
|
|
58
58
|
"fast-querystring": "^1.1.2",
|
|
@@ -92,5 +92,5 @@
|
|
|
92
92
|
"pino": ">=7.0.0",
|
|
93
93
|
"rxjs": "^7.0.0"
|
|
94
94
|
},
|
|
95
|
-
"gitHead": "
|
|
95
|
+
"gitHead": "ab3426c105b6b59a7a092a3a5ae1e563ea1253a4"
|
|
96
96
|
}
|