@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.
Files changed (36) hide show
  1. package/.cursor/rules/ai_directives.md +2 -2
  2. package/.cursor/rules/cursor-rules.md +4 -4
  3. package/.dynamo/logs/cicd-pipeline/output.log +1717 -1714
  4. package/.dynamo/logs/cicd-pipeline/status.json +30 -50
  5. package/.dynamo/pipeline.cicd.config.json +3 -1
  6. package/README.md +3 -3
  7. package/__documentations/2026-06-01-fr041-cors-middleware.md +2 -2
  8. package/__documentations/2026-06-01-fr047-p2p3-function-calling.md +3 -3
  9. package/__documentations/plans/BEDROCK-HYPERPLAN.md +1 -1
  10. package/build/_models/control-models/endpoint-params.control-model.d.ts.map +1 -1
  11. package/build/_models/control-models/endpoint-params.control-model.js +9 -0
  12. package/build/_models/control-models/endpoint-params.control-model.js.map +1 -1
  13. package/build/_modules/ai/_modules/ai-mock/index.js +1 -1
  14. package/build/_modules/ai/_modules/ai-mock/index.js.map +1 -1
  15. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.d.ts +1 -1
  16. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.js +1 -1
  17. package/build/_services/core/event-loop-diag.service.d.ts +6 -0
  18. package/build/_services/core/event-loop-diag.service.d.ts.map +1 -1
  19. package/build/_services/core/event-loop-diag.service.js +19 -1
  20. package/build/_services/core/event-loop-diag.service.js.map +1 -1
  21. package/build/_services/core/request-hunter.service.d.ts +74 -0
  22. package/build/_services/core/request-hunter.service.d.ts.map +1 -0
  23. package/build/_services/core/request-hunter.service.js +123 -0
  24. package/build/_services/core/request-hunter.service.js.map +1 -0
  25. package/build/index.d.ts +1 -0
  26. package/build/index.d.ts.map +1 -1
  27. package/build/index.js +1 -0
  28. package/build/index.js.map +1 -1
  29. package/package.json +2 -2
  30. package/src/_models/control-models/endpoint-params.control-model.ts +8 -0
  31. package/src/_modules/ai/_modules/ai-mock/index.ts +1 -1
  32. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +1 -1
  33. package/src/_services/core/event-loop-diag.service.ts +23 -1
  34. package/src/_services/core/request-hunter.service.spec.ts +124 -0
  35. package/src/_services/core/request-hunter.service.ts +157 -0
  36. 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';
@@ -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
@@ -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.126",
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.27",
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: Math.round(this.monitor.max / 1e6),
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