@futdevpro/nts-dynamo 1.15.126 → 1.15.128
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/.cursor/rules/ai_directives.md +2 -2
- package/.cursor/rules/cursor-rules.md +4 -4
- package/.dynamo/logs/cicd-pipeline/output.log +1717 -1714
- package/.dynamo/logs/cicd-pipeline/status.json +30 -50
- package/.dynamo/pipeline.cicd.config.json +3 -1
- package/README.md +3 -3
- package/__documentations/2026-06-01-fr041-cors-middleware.md +2 -2
- package/__documentations/2026-06-01-fr047-p2p3-function-calling.md +3 -3
- package/__documentations/plans/BEDROCK-HYPERPLAN.md +1 -1
- package/build/_models/control-models/endpoint-params.control-model.d.ts.map +1 -1
- package/build/_models/control-models/endpoint-params.control-model.js +9 -0
- package/build/_models/control-models/endpoint-params.control-model.js.map +1 -1
- package/build/_modules/ai/_modules/ai-mock/index.js +1 -1
- package/build/_modules/ai/_modules/ai-mock/index.js.map +1 -1
- package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.d.ts +1 -1
- package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.js +1 -1
- package/build/_services/core/event-loop-diag.service.d.ts +6 -0
- package/build/_services/core/event-loop-diag.service.d.ts.map +1 -1
- package/build/_services/core/event-loop-diag.service.js +19 -1
- package/build/_services/core/event-loop-diag.service.js.map +1 -1
- package/build/_services/core/request-hunter.service.d.ts +74 -0
- package/build/_services/core/request-hunter.service.d.ts.map +1 -0
- package/build/_services/core/request-hunter.service.js +123 -0
- package/build/_services/core/request-hunter.service.js.map +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/package.json +2 -2
- package/src/_models/control-models/endpoint-params.control-model.ts +8 -0
- package/src/_modules/ai/_modules/ai-mock/index.ts +1 -1
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +1 -1
- package/src/_services/core/event-loop-diag.service.ts +23 -1
- package/src/_services/core/request-hunter.service.spec.ts +124 -0
- package/src/_services/core/request-hunter.service.ts +157 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DyNTS_RequestHunter = void 0;
|
|
4
|
+
const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
|
|
5
|
+
const global_settings_const_1 = require("../../_collections/global-settings.const");
|
|
6
|
+
/**
|
|
7
|
+
* ISSUE-HUNTER: **melyik keres blokkolta az event-loopot?**
|
|
8
|
+
*
|
|
9
|
+
* ⚠️ MIERT KELLETT (mert incidens, overseer 2026-08-05): az event-loop 10-15 masodpercre
|
|
10
|
+
* megallt (`DyNTS_EventLoopDiag`: elLag max 10058-14839 ms), a `MemoryGuard` es a healthcheck
|
|
11
|
+
* ONMAGABAN egyiket sem tudta MIHEZ kotni. A diagnozis igy a nyers log 4893 sorabol tortent,
|
|
12
|
+
* orak alatt — holott a dontő jel MINDOSSZE 4 sor volt benne. A hianyzo kepesseg nem a MERES
|
|
13
|
+
* volt (az megvolt), hanem az ATTRIBUCIO: *mi futott, amikor megallt?*
|
|
14
|
+
*
|
|
15
|
+
* Ez a service ezt potolja, KET fuggetlen jellel:
|
|
16
|
+
*
|
|
17
|
+
* 1. **Lassu-keres onjelentes (a fo jel).** Amikor egy keres BEFEJEZODIK, ha tovabb tartott a
|
|
18
|
+
* kuszobnel, azonnal WARN-t ir a nevevel es az idejevel. A mai incidenst EZ egyetlen sorban
|
|
19
|
+
* megadta volna: `[REQ-HUNTER] SLOW getCdpReportDetails 10240ms`.
|
|
20
|
+
* ⚠️ Miert EZ a fo jel: a fagyas ALATT a diag-poll NEM fut (a loop all), tehat mire lefutna,
|
|
21
|
+
* a bunos keres mar befejezodott — az "in-flight pillanatkep" onmagaban ELKESNE.
|
|
22
|
+
*
|
|
23
|
+
* 2. **In-flight pillanatkep (a masodik jel).** Azokra az esetekre, amikor a keres MEG MINDIG
|
|
24
|
+
* fut (beragadt / vegtelen varakozas): a stall-detektor le tudja kerdezni, mi van eppen
|
|
25
|
+
* folyamatban es mennyi ideje.
|
|
26
|
+
*
|
|
27
|
+
* KOLTSEG: egy `Map`-beszuras + `Date.now()` keresenkent. Elhanyagolhato; ezert
|
|
28
|
+
* alapertelmezetten BE van kapcsolva (a mai incidens tanulsaga: ami nincs bekapcsolva, az pont
|
|
29
|
+
* az incidens alatt nem all rendelkezesre).
|
|
30
|
+
*
|
|
31
|
+
* Settings (`DyNTS_global_settings.requestHunter`):
|
|
32
|
+
* - `enabled?: boolean` default true
|
|
33
|
+
* - `slowRequestMs?: number` default 1000 — e felett WARN a keres vegen
|
|
34
|
+
* - `maxHistoryCount?: number` default 50 — a lassu-keres history merete
|
|
35
|
+
*/
|
|
36
|
+
class DyNTS_RequestHunter {
|
|
37
|
+
static instance;
|
|
38
|
+
static getInstance() {
|
|
39
|
+
if (!DyNTS_RequestHunter.instance) {
|
|
40
|
+
DyNTS_RequestHunter.instance = new DyNTS_RequestHunter();
|
|
41
|
+
}
|
|
42
|
+
return DyNTS_RequestHunter.instance;
|
|
43
|
+
}
|
|
44
|
+
nextId = 1;
|
|
45
|
+
inFlight = new Map();
|
|
46
|
+
slowHistory = [];
|
|
47
|
+
/** A settings-ertekek feloldasa (minden hivasnal, hogy a runtime-valtoztatas is hasson). */
|
|
48
|
+
getSettings() {
|
|
49
|
+
const s = global_settings_const_1.DyNTS_global_settings.requestHunter ?? {};
|
|
50
|
+
return {
|
|
51
|
+
enabled: s.enabled !== false,
|
|
52
|
+
slowRequestMs: typeof s.slowRequestMs === 'number' && s.slowRequestMs > 0 ? s.slowRequestMs : 1000,
|
|
53
|
+
maxHistoryCount: typeof s.maxHistoryCount === 'number' && s.maxHistoryCount > 0 ? s.maxHistoryCount : 50,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Keres kezdete. A visszaadott id-t az `end()`-nek kell atadni.
|
|
58
|
+
*
|
|
59
|
+
* @returns a keres id-ja, vagy 0 ha a hunter ki van kapcsolva (az `end(0)` no-op)
|
|
60
|
+
*/
|
|
61
|
+
begin(label) {
|
|
62
|
+
if (!this.getSettings().enabled) {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
const id = this.nextId++;
|
|
66
|
+
this.inFlight.set(id, { label: label, startedAt: Date.now() });
|
|
67
|
+
return id;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Keres vege. Ha a kuszobnel tovabb tartott, WARN + bekerul a history-ba.
|
|
71
|
+
* Hibatur: ismeretlen / 0 id eseten no-op.
|
|
72
|
+
*/
|
|
73
|
+
end(id) {
|
|
74
|
+
if (!id) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const entry = this.inFlight.get(id);
|
|
78
|
+
if (!entry) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.inFlight.delete(id);
|
|
82
|
+
const settings = this.getSettings();
|
|
83
|
+
const durationMs = Date.now() - entry.startedAt;
|
|
84
|
+
if (durationMs < settings.slowRequestMs) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.slowHistory.push({ at: Date.now(), label: entry.label, durationMs: durationMs });
|
|
88
|
+
if (this.slowHistory.length > settings.maxHistoryCount) {
|
|
89
|
+
this.slowHistory = this.slowHistory.slice(-settings.maxHistoryCount);
|
|
90
|
+
}
|
|
91
|
+
fsm_dynamo_1.DyFM_Log.warn(`[REQ-HUNTER] SLOW ${entry.label} ${durationMs}ms`
|
|
92
|
+
+ (this.inFlight.size ? ` (kozben ${this.inFlight.size} masik keres is futott)` : ''));
|
|
93
|
+
}
|
|
94
|
+
/** Az EPPEN futo keresek — a stall-detektor ebbol tudja, mi ragadt be. */
|
|
95
|
+
getInFlight(now = Date.now()) {
|
|
96
|
+
const out = [];
|
|
97
|
+
for (const entry of this.inFlight.values()) {
|
|
98
|
+
out.push({ label: entry.label, ageMs: now - entry.startedAt });
|
|
99
|
+
}
|
|
100
|
+
return out.sort((a, b) => b.ageMs - a.ageMs);
|
|
101
|
+
}
|
|
102
|
+
/** A kozelmult lassu keresei (gorgo history) — `/server/diag`-ba is kitehető. */
|
|
103
|
+
getSlowHistory() {
|
|
104
|
+
return [...this.slowHistory];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Ember-olvashato in-flight osszefoglalo a stall-loghoz.
|
|
108
|
+
* Ures listanal expliciten ezt mondja — mert az IS informacio: a blokkolo mar befejezodott,
|
|
109
|
+
* tehat a lassu-keres onjelentest (1. jel) kell nezni.
|
|
110
|
+
*/
|
|
111
|
+
describeInFlight(now = Date.now()) {
|
|
112
|
+
const list = this.getInFlight(now);
|
|
113
|
+
if (!list.length) {
|
|
114
|
+
return 'nincs futo keres (a blokkolo mar befejezodott — lasd a [REQ-HUNTER] SLOW sorokat)';
|
|
115
|
+
}
|
|
116
|
+
return list
|
|
117
|
+
.slice(0, 5)
|
|
118
|
+
.map((r) => `${r.label} (${r.ageMs}ms)`)
|
|
119
|
+
.join(', ');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
exports.DyNTS_RequestHunter = DyNTS_RequestHunter;
|
|
123
|
+
//# sourceMappingURL=request-hunter.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-hunter.service.js","sourceRoot":"","sources":["../../../src/_services/core/request-hunter.service.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from './_collections/signed-url.util';
|
|
|
26
26
|
export * from './_collections/client-safe-error.util';
|
|
27
27
|
export * from './_collections/load-shed.util';
|
|
28
28
|
export * from './_services/core/event-loop-diag.service';
|
|
29
|
+
export * from './_services/core/request-hunter.service';
|
|
29
30
|
export * from './_services/core/db-stats.service';
|
|
30
31
|
export * from './_services/core/diagnostics.service';
|
|
31
32
|
export * from './_models/control-models/api-call-params.control-model';
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2BA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,qDAAqD,CAAC;AACpE,cAAc,6CAA6C,CAAC;AAC5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sCAAsC,CAAC;AAIrD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAK7C,mEAAmE;AACnE,cAAc,uDAAuD,CAAC;AACtE,cAAc,qDAAqD,CAAC;AACpE,cAAc,wDAAwD,CAAC;AACvE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,wDAAwD,CAAC;AACvE,cAAc,yDAAyD,CAAC;AACxE,cAAc,uDAAuD,CAAC;AACtE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC;AACzE,cAAc,iDAAiD,CAAC;AAChE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0CAA0C,CAAC;AACzD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AAGrD,cAAc,wDAAwD,CAAC;AACvE,cAAc,gEAAgE,CAAA;AAC9E,cAAc,mDAAmD,CAAC;AAClE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,wDAAwD,CAAC;AACvE,cAAc,sDAAsD,CAAC;AACrE,cAAc,uDAAuD,CAAC;AAGtE,cAAc,gCAAgC,CAAC;AAG/C,cAAc,mDAAmD,CAAC;AAKlE,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oDAAoD,CAAC;AACnE,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2CAA2C,CAAC;AAG1D,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yCAAyC,CAAC;AACxD,cAAc,oCAAoC,CAAC;AAGnD,cAAc,+BAA+B,CAAC;AAG9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,0CAA0C,CAAC;AAGzD,cAAc,mCAAmC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2BA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,qDAAqD,CAAC;AACpE,cAAc,6CAA6C,CAAC;AAC5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sCAAsC,CAAC;AAIrD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAK7C,mEAAmE;AACnE,cAAc,uDAAuD,CAAC;AACtE,cAAc,qDAAqD,CAAC;AACpE,cAAc,wDAAwD,CAAC;AACvE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,wDAAwD,CAAC;AACvE,cAAc,yDAAyD,CAAC;AACxE,cAAc,uDAAuD,CAAC;AACtE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC;AACzE,cAAc,iDAAiD,CAAC;AAChE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0CAA0C,CAAC;AACzD,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AAGrD,cAAc,wDAAwD,CAAC;AACvE,cAAc,gEAAgE,CAAA;AAC9E,cAAc,mDAAmD,CAAC;AAClE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,wDAAwD,CAAC;AACvE,cAAc,sDAAsD,CAAC;AACrE,cAAc,uDAAuD,CAAC;AAGtE,cAAc,gCAAgC,CAAC;AAG/C,cAAc,mDAAmD,CAAC;AAKlE,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oDAAoD,CAAC;AACnE,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2CAA2C,CAAC;AAG1D,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yCAAyC,CAAC;AACxD,cAAc,oCAAoC,CAAC;AAGnD,cAAc,+BAA+B,CAAC;AAG9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,0CAA0C,CAAC;AAGzD,cAAc,mCAAmC,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -55,6 +55,7 @@ tslib_1.__exportStar(require("./_collections/signed-url.util"), exports);
|
|
|
55
55
|
tslib_1.__exportStar(require("./_collections/client-safe-error.util"), exports);
|
|
56
56
|
tslib_1.__exportStar(require("./_collections/load-shed.util"), exports);
|
|
57
57
|
tslib_1.__exportStar(require("./_services/core/event-loop-diag.service"), exports);
|
|
58
|
+
tslib_1.__exportStar(require("./_services/core/request-hunter.service"), exports);
|
|
58
59
|
tslib_1.__exportStar(require("./_services/core/db-stats.service"), exports);
|
|
59
60
|
tslib_1.__exportStar(require("./_services/core/diagnostics.service"), exports);
|
|
60
61
|
// models/CONTROL MODELS
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;IAsBI;;;AAEJ,cAAc;AACd,sEAA4C;AAC5C,wFAA8D;AAC9D,8FAAoE;AACpE,sFAA4D;AAC5D,mFAAyD;AACzD,uFAA6D;AAC7D,+EAAqD;AAGrD,QAAQ;AACR,wEAA8C;AAC9C,8EAAoD;AACpD,8EAAoD;AACpD,uEAA6C;AAG7C,6CAA6C;AAE7C,mEAAmE;AACnE,gGAAsE;AACtE,8FAAoE;AACpE,iGAAuE;AACvE,yFAA+D;AAC/D,iGAAuE;AACvE,kGAAwE;AACxE,gGAAsE;AACtE,uFAA6D;AAC7D,mGAAyE;AACzE,0FAAgE;AAChE,yFAA+D;AAC/D,+EAAqD;AACrD,yEAA+C;AAC/C,gFAAsD;AACtD,wEAA8C;AAC9C,mFAAyD;AACzD,4EAAkD;AAClD,+EAAqD;AAErD,wBAAwB;AACxB,iGAAuE;AACvE,yGAA8E;AAC9E,4FAAkE;AAClE,qGAA2E;AAC3E,iGAAuE;AACvE,+FAAqE;AACrE,gGAAsE;AAEtE,eAAe;AACf,yEAA+C;AAE/C,qBAAqB;AACrB,4FAAkE;AAGlE,WAAW;AACX,gBAAgB;AAChB,uEAA6C;AAC7C,wEAA8C;AAE9C,yEAA+C;AAC/C,6FAAmE;AACnE,0EAAgD;AAChD,gFAAsD;AAEtD,sFAA4D;AAC5D,oFAA0D;AAE1D,gBAAgB;AAChB,4EAAkD;AAClD,gFAAsD;AACtD,wEAA8C;AAC9C,sEAA4C;AAC5C,kFAAwD;AACxD,6EAAmD;AAEnD,kBAAkB;AAClB,wEAA8C;AAE9C,iBAAiB;AACjB,+EAAqD;AACrD,mFAAyD;AAEzD,kBAAkB;AAClB,4EAAkD"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;IAsBI;;;AAEJ,cAAc;AACd,sEAA4C;AAC5C,wFAA8D;AAC9D,8FAAoE;AACpE,sFAA4D;AAC5D,mFAAyD;AACzD,uFAA6D;AAC7D,+EAAqD;AAGrD,QAAQ;AACR,wEAA8C;AAC9C,8EAAoD;AACpD,8EAAoD;AACpD,uEAA6C;AAG7C,6CAA6C;AAE7C,mEAAmE;AACnE,gGAAsE;AACtE,8FAAoE;AACpE,iGAAuE;AACvE,yFAA+D;AAC/D,iGAAuE;AACvE,kGAAwE;AACxE,gGAAsE;AACtE,uFAA6D;AAC7D,mGAAyE;AACzE,0FAAgE;AAChE,yFAA+D;AAC/D,+EAAqD;AACrD,yEAA+C;AAC/C,gFAAsD;AACtD,wEAA8C;AAC9C,mFAAyD;AACzD,kFAAwD;AACxD,4EAAkD;AAClD,+EAAqD;AAErD,wBAAwB;AACxB,iGAAuE;AACvE,yGAA8E;AAC9E,4FAAkE;AAClE,qGAA2E;AAC3E,iGAAuE;AACvE,+FAAqE;AACrE,gGAAsE;AAEtE,eAAe;AACf,yEAA+C;AAE/C,qBAAqB;AACrB,4FAAkE;AAGlE,WAAW;AACX,gBAAgB;AAChB,uEAA6C;AAC7C,wEAA8C;AAE9C,yEAA+C;AAC/C,6FAAmE;AACnE,0EAAgD;AAChD,gFAAsD;AAEtD,sFAA4D;AAC5D,oFAA0D;AAE1D,gBAAgB;AAChB,4EAAkD;AAClD,gFAAsD;AACtD,wEAA8C;AAC9C,sEAA4C;AAC5C,kFAAwD;AACxD,6EAAmD;AAEnD,kBAAkB;AAClB,wEAA8C;AAE9C,iBAAiB;AACjB,+EAAqD;AACrD,mFAAyD;AAEzD,kBAAkB;AAClB,4EAAkD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futdevpro/nts-dynamo",
|
|
3
|
-
"version": "01.15.
|
|
3
|
+
"version": "01.15.128",
|
|
4
4
|
"description": "Dynamic NodeTS (NodeJS-Typescript), MongoDB Backend System Framework by Future Development Program Ltd.",
|
|
5
5
|
"DyBu_settings": {
|
|
6
6
|
"packageType": "server-package",
|
|
@@ -378,7 +378,7 @@
|
|
|
378
378
|
"@anthropic-ai/sdk": "~0.39.0",
|
|
379
379
|
"@modelcontextprotocol/sdk": "~1.29.0",
|
|
380
380
|
"better-sqlite3": "~12.4.1",
|
|
381
|
-
"@futdevpro/fsm-dynamo": "1.16.
|
|
381
|
+
"@futdevpro/fsm-dynamo": "1.16.30",
|
|
382
382
|
"@types/express": "4.17.21",
|
|
383
383
|
"@types/geoip-lite": "~1.4.1",
|
|
384
384
|
"@types/node": "~24.1.0",
|
|
@@ -10,6 +10,7 @@ import { DyNTS_global_settings } from '../../_collections/global-settings.const'
|
|
|
10
10
|
import { DyNTS_ClientSafeError_Util } from '../../_collections/client-safe-error.util';
|
|
11
11
|
import { DyNTS_RouteSecurity } from '../../_enums/route-security.enum';
|
|
12
12
|
import { DyNTS_GlobalService } from '../../_services/core/global.service';
|
|
13
|
+
import { DyNTS_RequestHunter } from '../../_services/core/request-hunter.service';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* High level endpoint for API
|
|
@@ -215,6 +216,11 @@ export class DyNTS_Endpoint_Params<
|
|
|
215
216
|
let issuer: string;
|
|
216
217
|
|
|
217
218
|
return async (req: Request, res: Response): Promise<void> => {
|
|
219
|
+
// ISSUE-HUNTER (2026-08-05) — keres-szintu attribucio. Ez a KOZPONTI vegrehajtasi pont,
|
|
220
|
+
// minden endpoint ezen megy at, ezert itt (es CSAK itt) merunk. Koltseg: egy Map-beszuras
|
|
221
|
+
// + Date.now(). A `finally` garantalja, hogy hiba/early-return eseten se szivarogjon be-
|
|
222
|
+
// jegyzes. Reszletes indoklas: `DyNTS_RequestHunter`.
|
|
223
|
+
const hunterId: number = DyNTS_RequestHunter.getInstance().begin(this.name);
|
|
218
224
|
try {
|
|
219
225
|
let issuer: string;
|
|
220
226
|
try {
|
|
@@ -289,6 +295,8 @@ export class DyNTS_Endpoint_Params<
|
|
|
289
295
|
}
|
|
290
296
|
} catch (error) {
|
|
291
297
|
this.error(req, res, error, issuer);
|
|
298
|
+
} finally {
|
|
299
|
+
DyNTS_RequestHunter.getInstance().end(hunterId);
|
|
292
300
|
}
|
|
293
301
|
};
|
|
294
302
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// AI Mocking System — provider-faithful mock-service + fixture-store (Layer B) a valódi AI-hívások
|
|
5
5
|
// kiváltására teszt/CI/lokál-fejlesztésben. A Layer A (per-model config-registry + validátor) a FR-048
|
|
6
6
|
// (`DyFM_AI_ModelSettingsSchema` + reconciler) — az ai-mock azt FOGYASZTJA a provider-faithful
|
|
7
|
-
// error-reprodukcióhoz. Terv: `documentations/plans/ai-mocking-system/HYPERPLAN.md`.
|
|
7
|
+
// error-reprodukcióhoz. Terv: `fdp-documentations/plans/ai-mocking-system/HYPERPLAN.md`.
|
|
8
8
|
//
|
|
9
9
|
// SCAFFOLD (Cikl. 2, 2026-07-21): a modul-váz + a meglévő determinisztikus embedding-mock re-exportja.
|
|
10
10
|
// A további szolgáltatások (fixture-store, mock-service, coverage) MP-3..MP-6 során kerülnek ide;
|
|
@@ -718,7 +718,7 @@ export class DyNTS_OAI_LLM_ServiceBase extends DyNTS_AI_LLM_ServiceBase {
|
|
|
718
718
|
* a heurisztikat CSAK akkor hasznalja, ha az adott modellhez nincs schema (regi fsm-verzio / ismeretlen
|
|
719
719
|
* modell). Amint a populalt schema mindenhol elerheto, ez a metodus elhagyhato.
|
|
720
720
|
*
|
|
721
|
-
* Reszletek: `documentations/plans/ai-mocking-system/CAPTURE-FINDINGS.md` §1.
|
|
721
|
+
* Reszletek: `fdp-documentations/plans/ai-mocking-system/CAPTURE-FINDINGS.md` §1.
|
|
722
722
|
*/
|
|
723
723
|
protected isReasoningModel(modelId: string): boolean {
|
|
724
724
|
return /^gpt-5/.test(modelId) || /^o[0-9]/.test(modelId);
|
|
@@ -3,6 +3,7 @@ import { monitorEventLoopDelay, IntervalHistogram } from 'perf_hooks';
|
|
|
3
3
|
import { DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
4
4
|
|
|
5
5
|
import { DyNTS_global_settings } from '../../_collections/global-settings.const';
|
|
6
|
+
import { DyNTS_RequestHunter } from './request-hunter.service';
|
|
6
7
|
|
|
7
8
|
/** Egy event-loop-lag mintavétel (a gördülő history eleme). */
|
|
8
9
|
export interface DyNTS_EventLoopSample {
|
|
@@ -32,6 +33,13 @@ export interface DyNTS_EventLoopSample {
|
|
|
32
33
|
*/
|
|
33
34
|
export class DyNTS_EventLoopDiag {
|
|
34
35
|
|
|
36
|
+
/**
|
|
37
|
+
* E fölött a lag fölött írunk ki issue-hunter attribúciót (`[EL-STALL]`).
|
|
38
|
+
* 1000ms: egy másodperces loop-megállás már valódi tünet (a normál érték 20-50ms),
|
|
39
|
+
* de elég magas ahhoz, hogy a szokásos GC-tüskék ne spam-eljenek.
|
|
40
|
+
*/
|
|
41
|
+
static readonly STALL_ATTRIBUTION_MS: number = 1000;
|
|
42
|
+
|
|
35
43
|
private static instance: DyNTS_EventLoopDiag;
|
|
36
44
|
|
|
37
45
|
static getInstance(): DyNTS_EventLoopDiag {
|
|
@@ -73,15 +81,29 @@ export class DyNTS_EventLoopDiag {
|
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
// a histogram ns-ben mér → ms-re váltunk; poll után reset (ablakonkénti kép)
|
|
84
|
+
const maxMs: number = Math.round(this.monitor.max / 1e6);
|
|
76
85
|
this.history.push({
|
|
77
86
|
at: Date.now(),
|
|
78
87
|
p50Ms: Math.round(this.monitor.percentile(50) / 1e6),
|
|
79
88
|
p95Ms: Math.round(this.monitor.percentile(95) / 1e6),
|
|
80
|
-
maxMs:
|
|
89
|
+
maxMs: maxMs,
|
|
81
90
|
activeHandles: this.getActiveHandleCount(),
|
|
82
91
|
});
|
|
83
92
|
this.monitor.reset();
|
|
84
93
|
|
|
94
|
+
// ISSUE-HUNTER ATTRIBÚCIÓ (2026-08-05) — a mérés eddig csak azt mondta meg, HOGY megállt
|
|
95
|
+
// a loop, azt NEM, hogy MITŐL. Stall esetén kiírjuk az ÉPPEN futó kéréseket.
|
|
96
|
+
//
|
|
97
|
+
// ⚠️ Fontos korlát, amit a szöveg is kimond: a fagyás ALATT ez a poll NEM fut, ezért ha a
|
|
98
|
+
// blokkoló kérés időközben befejeződött, az in-flight lista ÜRES lesz. Ezért a `describeInFlight()`
|
|
99
|
+
// ilyenkor expliciten a `[REQ-HUNTER] SLOW` sorokra irányít — az a FŐ jel, ez a másodlagos.
|
|
100
|
+
if (maxMs >= DyNTS_EventLoopDiag.STALL_ATTRIBUTION_MS) {
|
|
101
|
+
DyFM_Log.warn(
|
|
102
|
+
`[EL-STALL] event-loop megallas ${maxMs}ms — futo keresek: `
|
|
103
|
+
+ DyNTS_RequestHunter.getInstance().describeInFlight(),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
85
107
|
if (this.history.length > maxHistoryCount) {
|
|
86
108
|
this.history = this.history.slice(-maxHistoryCount);
|
|
87
109
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { DyNTS_global_settings } from '../../_collections/global-settings.const';
|
|
2
|
+
import { DyNTS_InFlightRequest, DyNTS_RequestHunter, DyNTS_SlowRequestSample } from './request-hunter.service';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ISSUE-HUNTER — keres-szintu attribucio.
|
|
6
|
+
*
|
|
7
|
+
* A mert incidens (overseer 2026-08-05): az event-loop 10-15 mp-re megallt, de SEMMI nem mondta
|
|
8
|
+
* meg, MELYIK keres okozta. A diagnozis 4893 nyers log-sorbol tortent. Ez a service azt a
|
|
9
|
+
* kepesseget adja, ami hianyzott: a lassu keres MAGA jelenti magat, nevvel es idovel.
|
|
10
|
+
*/
|
|
11
|
+
describe('| DyNTS_RequestHunter', () => {
|
|
12
|
+
|
|
13
|
+
let hunter: DyNTS_RequestHunter;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
hunter = DyNTS_RequestHunter.getInstance();
|
|
17
|
+
// Tiszta lap: a bennmaradt in-flight bejegyzeseket lezarjuk
|
|
18
|
+
for (let i = 0; i < 50; i++) { hunter.end(i); }
|
|
19
|
+
(DyNTS_global_settings as { requestHunter?: unknown }).requestHunter = { enabled: true, slowRequestMs: 20 };
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
delete (DyNTS_global_settings as { requestHunter?: unknown }).requestHunter;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const wait = (ms: number): Promise<void> =>
|
|
27
|
+
new Promise<void>((r: () => void): void => { setTimeout(r, ms); });
|
|
28
|
+
|
|
29
|
+
describe('| in-flight nyilvantartas', () => {
|
|
30
|
+
|
|
31
|
+
it('| a futo keres LATSZIK, a befejezett NEM', () => {
|
|
32
|
+
// Arrange & Act
|
|
33
|
+
const id: number = hunter.begin('getCdpReportDetails');
|
|
34
|
+
|
|
35
|
+
// Assert — fut
|
|
36
|
+
const during: DyNTS_InFlightRequest[] = hunter.getInFlight();
|
|
37
|
+
expect(during.some((r: DyNTS_InFlightRequest): boolean => r.label === 'getCdpReportDetails')).toBeTrue();
|
|
38
|
+
|
|
39
|
+
// Act — vege
|
|
40
|
+
hunter.end(id);
|
|
41
|
+
|
|
42
|
+
// Assert — mar nem
|
|
43
|
+
expect(hunter.getInFlight().some((r: DyNTS_InFlightRequest): boolean => r.label === 'getCdpReportDetails'))
|
|
44
|
+
.toBeFalse();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('| a leghosszabb ideje futo keres van ELOL (az a gyanus)', async (): Promise<void> => {
|
|
48
|
+
// Arrange
|
|
49
|
+
const first: number = hunter.begin('regota-fut');
|
|
50
|
+
await wait(30);
|
|
51
|
+
const second: number = hunter.begin('most-indult');
|
|
52
|
+
|
|
53
|
+
// Act
|
|
54
|
+
const list: DyNTS_InFlightRequest[] = hunter.getInFlight();
|
|
55
|
+
|
|
56
|
+
// Assert
|
|
57
|
+
expect(list[0].label).toBe('regota-fut');
|
|
58
|
+
expect(list[0].ageMs).toBeGreaterThanOrEqual(list[1].ageMs);
|
|
59
|
+
|
|
60
|
+
hunter.end(first);
|
|
61
|
+
hunter.end(second);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('| lassu-keres onjelentes (a FO jel)', () => {
|
|
66
|
+
|
|
67
|
+
it('| a kuszob folotti keres bekerul a history-ba, nevvel es idovel', async (): Promise<void> => {
|
|
68
|
+
// Arrange — 20ms a kuszob (beforeEach)
|
|
69
|
+
const id: number = hunter.begin('getCdpReportDetails');
|
|
70
|
+
await wait(45);
|
|
71
|
+
|
|
72
|
+
// Act
|
|
73
|
+
hunter.end(id);
|
|
74
|
+
|
|
75
|
+
// Assert — EZ az a sor, ami a mai incidenst egy lepesben megadta volna
|
|
76
|
+
const slow: DyNTS_SlowRequestSample[] = hunter.getSlowHistory();
|
|
77
|
+
const found: DyNTS_SlowRequestSample | undefined =
|
|
78
|
+
slow.find((s: DyNTS_SlowRequestSample): boolean => s.label === 'getCdpReportDetails');
|
|
79
|
+
expect(found).toBeDefined();
|
|
80
|
+
expect(found!.durationMs).toBeGreaterThanOrEqual(20);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('| a GYORS keres NEM kerul a history-ba (nincs log-flood)', async (): Promise<void> => {
|
|
84
|
+
// Arrange
|
|
85
|
+
const before: number = hunter.getSlowHistory().length;
|
|
86
|
+
const id: number = hunter.begin('gyors-keres');
|
|
87
|
+
|
|
88
|
+
// Act
|
|
89
|
+
hunter.end(id);
|
|
90
|
+
|
|
91
|
+
// Assert
|
|
92
|
+
expect(hunter.getSlowHistory().length).toBe(before);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('| robusztussag', () => {
|
|
97
|
+
|
|
98
|
+
it('| kikapcsolva a begin 0-t ad, es az end(0) no-op (nem dob)', () => {
|
|
99
|
+
// Arrange
|
|
100
|
+
(DyNTS_global_settings as { requestHunter?: unknown }).requestHunter = { enabled: false };
|
|
101
|
+
|
|
102
|
+
// Act & Assert
|
|
103
|
+
const id: number = hunter.begin('barmi');
|
|
104
|
+
expect(id).toBe(0);
|
|
105
|
+
expect((): void => hunter.end(0)).not.toThrow();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('| ismeretlen id-re az end no-op (dupla-end / elveszett id sem szivarogtat)', () => {
|
|
109
|
+
// Act & Assert
|
|
110
|
+
expect((): void => hunter.end(999999)).not.toThrow();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('| ures in-flight eseten a leiras a SLOW-sorokra iranyit (ez is informacio)', () => {
|
|
114
|
+
// Arrange — minden lezarva
|
|
115
|
+
for (let i = 0; i < 50; i++) { hunter.end(i); }
|
|
116
|
+
|
|
117
|
+
// Act
|
|
118
|
+
const text: string = hunter.describeInFlight();
|
|
119
|
+
|
|
120
|
+
// Assert — a fagyas ALATT a poll nem fut, ezert az ures lista VARHATO; a szoveg ezt megmondja
|
|
121
|
+
expect(text).toContain('SLOW');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
2
|
+
|
|
3
|
+
import { DyNTS_global_settings } from '../../_collections/global-settings.const';
|
|
4
|
+
|
|
5
|
+
/** Egy eppen futo keres a hunter nyilvantartasaban. */
|
|
6
|
+
export interface DyNTS_InFlightRequest {
|
|
7
|
+
/** Az endpoint neve (`DyNTS_Endpoint_Params.name`). */
|
|
8
|
+
label: string;
|
|
9
|
+
/** Mennyi ideje fut (ms). */
|
|
10
|
+
ageMs: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Egy mar befejezodott LASSU keres (gorgo history). */
|
|
14
|
+
export interface DyNTS_SlowRequestSample {
|
|
15
|
+
at: number;
|
|
16
|
+
label: string;
|
|
17
|
+
durationMs: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* ISSUE-HUNTER: **melyik keres blokkolta az event-loopot?**
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ MIERT KELLETT (mert incidens, overseer 2026-08-05): az event-loop 10-15 masodpercre
|
|
24
|
+
* megallt (`DyNTS_EventLoopDiag`: elLag max 10058-14839 ms), a `MemoryGuard` es a healthcheck
|
|
25
|
+
* ONMAGABAN egyiket sem tudta MIHEZ kotni. A diagnozis igy a nyers log 4893 sorabol tortent,
|
|
26
|
+
* orak alatt — holott a dontő jel MINDOSSZE 4 sor volt benne. A hianyzo kepesseg nem a MERES
|
|
27
|
+
* volt (az megvolt), hanem az ATTRIBUCIO: *mi futott, amikor megallt?*
|
|
28
|
+
*
|
|
29
|
+
* Ez a service ezt potolja, KET fuggetlen jellel:
|
|
30
|
+
*
|
|
31
|
+
* 1. **Lassu-keres onjelentes (a fo jel).** Amikor egy keres BEFEJEZODIK, ha tovabb tartott a
|
|
32
|
+
* kuszobnel, azonnal WARN-t ir a nevevel es az idejevel. A mai incidenst EZ egyetlen sorban
|
|
33
|
+
* megadta volna: `[REQ-HUNTER] SLOW getCdpReportDetails 10240ms`.
|
|
34
|
+
* ⚠️ Miert EZ a fo jel: a fagyas ALATT a diag-poll NEM fut (a loop all), tehat mire lefutna,
|
|
35
|
+
* a bunos keres mar befejezodott — az "in-flight pillanatkep" onmagaban ELKESNE.
|
|
36
|
+
*
|
|
37
|
+
* 2. **In-flight pillanatkep (a masodik jel).** Azokra az esetekre, amikor a keres MEG MINDIG
|
|
38
|
+
* fut (beragadt / vegtelen varakozas): a stall-detektor le tudja kerdezni, mi van eppen
|
|
39
|
+
* folyamatban es mennyi ideje.
|
|
40
|
+
*
|
|
41
|
+
* KOLTSEG: egy `Map`-beszuras + `Date.now()` keresenkent. Elhanyagolhato; ezert
|
|
42
|
+
* alapertelmezetten BE van kapcsolva (a mai incidens tanulsaga: ami nincs bekapcsolva, az pont
|
|
43
|
+
* az incidens alatt nem all rendelkezesre).
|
|
44
|
+
*
|
|
45
|
+
* Settings (`DyNTS_global_settings.requestHunter`):
|
|
46
|
+
* - `enabled?: boolean` default true
|
|
47
|
+
* - `slowRequestMs?: number` default 1000 — e felett WARN a keres vegen
|
|
48
|
+
* - `maxHistoryCount?: number` default 50 — a lassu-keres history merete
|
|
49
|
+
*/
|
|
50
|
+
export class DyNTS_RequestHunter {
|
|
51
|
+
|
|
52
|
+
private static instance: DyNTS_RequestHunter;
|
|
53
|
+
|
|
54
|
+
static getInstance(): DyNTS_RequestHunter {
|
|
55
|
+
if (!DyNTS_RequestHunter.instance) {
|
|
56
|
+
DyNTS_RequestHunter.instance = new DyNTS_RequestHunter();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return DyNTS_RequestHunter.instance;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private nextId: number = 1;
|
|
63
|
+
private readonly inFlight: Map<number, { label: string; startedAt: number }> = new Map();
|
|
64
|
+
private slowHistory: DyNTS_SlowRequestSample[] = [];
|
|
65
|
+
|
|
66
|
+
/** A settings-ertekek feloldasa (minden hivasnal, hogy a runtime-valtoztatas is hasson). */
|
|
67
|
+
private getSettings(): { enabled: boolean; slowRequestMs: number; maxHistoryCount: number } {
|
|
68
|
+
const s: { enabled?: boolean; slowRequestMs?: number; maxHistoryCount?: number } =
|
|
69
|
+
(DyNTS_global_settings as { requestHunter?: Record<string, unknown> }).requestHunter ?? {};
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
enabled: s.enabled !== false,
|
|
73
|
+
slowRequestMs: typeof s.slowRequestMs === 'number' && s.slowRequestMs > 0 ? s.slowRequestMs : 1000,
|
|
74
|
+
maxHistoryCount: typeof s.maxHistoryCount === 'number' && s.maxHistoryCount > 0 ? s.maxHistoryCount : 50,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Keres kezdete. A visszaadott id-t az `end()`-nek kell atadni.
|
|
80
|
+
*
|
|
81
|
+
* @returns a keres id-ja, vagy 0 ha a hunter ki van kapcsolva (az `end(0)` no-op)
|
|
82
|
+
*/
|
|
83
|
+
begin(label: string): number {
|
|
84
|
+
if (!this.getSettings().enabled) {
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const id: number = this.nextId++;
|
|
89
|
+
this.inFlight.set(id, { label: label, startedAt: Date.now() });
|
|
90
|
+
|
|
91
|
+
return id;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Keres vege. Ha a kuszobnel tovabb tartott, WARN + bekerul a history-ba.
|
|
96
|
+
* Hibatur: ismeretlen / 0 id eseten no-op.
|
|
97
|
+
*/
|
|
98
|
+
end(id: number): void {
|
|
99
|
+
if (!id) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const entry: { label: string; startedAt: number } | undefined = this.inFlight.get(id);
|
|
104
|
+
if (!entry) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.inFlight.delete(id);
|
|
108
|
+
|
|
109
|
+
const settings: { slowRequestMs: number; maxHistoryCount: number } = this.getSettings();
|
|
110
|
+
const durationMs: number = Date.now() - entry.startedAt;
|
|
111
|
+
if (durationMs < settings.slowRequestMs) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.slowHistory.push({ at: Date.now(), label: entry.label, durationMs: durationMs });
|
|
116
|
+
if (this.slowHistory.length > settings.maxHistoryCount) {
|
|
117
|
+
this.slowHistory = this.slowHistory.slice(-settings.maxHistoryCount);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
DyFM_Log.warn(
|
|
121
|
+
`[REQ-HUNTER] SLOW ${entry.label} ${durationMs}ms`
|
|
122
|
+
+ (this.inFlight.size ? ` (kozben ${this.inFlight.size} masik keres is futott)` : ''),
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Az EPPEN futo keresek — a stall-detektor ebbol tudja, mi ragadt be. */
|
|
127
|
+
getInFlight(now: number = Date.now()): DyNTS_InFlightRequest[] {
|
|
128
|
+
const out: DyNTS_InFlightRequest[] = [];
|
|
129
|
+
for (const entry of this.inFlight.values()) {
|
|
130
|
+
out.push({ label: entry.label, ageMs: now - entry.startedAt });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return out.sort((a: DyNTS_InFlightRequest, b: DyNTS_InFlightRequest): number => b.ageMs - a.ageMs);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** A kozelmult lassu keresei (gorgo history) — `/server/diag`-ba is kitehető. */
|
|
137
|
+
getSlowHistory(): DyNTS_SlowRequestSample[] {
|
|
138
|
+
return [...this.slowHistory];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Ember-olvashato in-flight osszefoglalo a stall-loghoz.
|
|
143
|
+
* Ures listanal expliciten ezt mondja — mert az IS informacio: a blokkolo mar befejezodott,
|
|
144
|
+
* tehat a lassu-keres onjelentest (1. jel) kell nezni.
|
|
145
|
+
*/
|
|
146
|
+
describeInFlight(now: number = Date.now()): string {
|
|
147
|
+
const list: DyNTS_InFlightRequest[] = this.getInFlight(now);
|
|
148
|
+
if (!list.length) {
|
|
149
|
+
return 'nincs futo keres (a blokkolo mar befejezodott — lasd a [REQ-HUNTER] SLOW sorokat)';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return list
|
|
153
|
+
.slice(0, 5)
|
|
154
|
+
.map((r: DyNTS_InFlightRequest): string => `${r.label} (${r.ageMs}ms)`)
|
|
155
|
+
.join(', ');
|
|
156
|
+
}
|
|
157
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -60,6 +60,7 @@ export * from './_collections/signed-url.util';
|
|
|
60
60
|
export * from './_collections/client-safe-error.util';
|
|
61
61
|
export * from './_collections/load-shed.util';
|
|
62
62
|
export * from './_services/core/event-loop-diag.service';
|
|
63
|
+
export * from './_services/core/request-hunter.service';
|
|
63
64
|
export * from './_services/core/db-stats.service';
|
|
64
65
|
export * from './_services/core/diagnostics.service';
|
|
65
66
|
|