repro-nest 0.0.199 → 0.0.201
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/dist/index.js +28 -12
- package/package.json +1 -1
- package/src/index.ts +29 -12
package/dist/index.js
CHANGED
|
@@ -1148,12 +1148,15 @@ function reproMiddleware(cfg) {
|
|
|
1148
1148
|
let unsubscribe;
|
|
1149
1149
|
let flushed = false;
|
|
1150
1150
|
let finished = false;
|
|
1151
|
+
let finishedAt = null;
|
|
1152
|
+
let lastEventAt = Date.now();
|
|
1151
1153
|
let idleTimer = null;
|
|
1152
1154
|
let hardStopTimer = null;
|
|
1153
1155
|
let drainTimer = null;
|
|
1154
1156
|
let flushPayload = null;
|
|
1155
1157
|
const activeSpans = new Set();
|
|
1156
1158
|
let anonymousSpanDepth = 0;
|
|
1159
|
+
const ACTIVE_SPAN_FORCE_FLUSH_MS = 30000; // safety guard against leaks
|
|
1157
1160
|
const clearTimers = () => {
|
|
1158
1161
|
if (idleTimer) {
|
|
1159
1162
|
try {
|
|
@@ -1178,7 +1181,7 @@ function reproMiddleware(cfg) {
|
|
|
1178
1181
|
}
|
|
1179
1182
|
};
|
|
1180
1183
|
const hasActiveWork = () => activeSpans.size > 0 || anonymousSpanDepth > 0;
|
|
1181
|
-
const scheduleIdleFlush = () => {
|
|
1184
|
+
const scheduleIdleFlush = (delay = TRACE_IDLE_FLUSH_MS) => {
|
|
1182
1185
|
if (!finished || flushed)
|
|
1183
1186
|
return;
|
|
1184
1187
|
if (hasActiveWork())
|
|
@@ -1189,15 +1192,30 @@ function reproMiddleware(cfg) {
|
|
|
1189
1192
|
}
|
|
1190
1193
|
catch { }
|
|
1191
1194
|
}
|
|
1192
|
-
idleTimer = setTimeout(() => doFlush(false),
|
|
1195
|
+
idleTimer = setTimeout(() => doFlush(false), delay);
|
|
1193
1196
|
};
|
|
1194
1197
|
const doFlush = (force = false) => {
|
|
1195
1198
|
if (flushed)
|
|
1196
1199
|
return;
|
|
1197
|
-
|
|
1198
|
-
|
|
1200
|
+
const now = Date.now();
|
|
1201
|
+
const stillActive = hasActiveWork();
|
|
1202
|
+
const quietMs = now - lastEventAt;
|
|
1203
|
+
const waitedFinish = finishedAt === null ? 0 : now - finishedAt;
|
|
1204
|
+
// If work is still active and we haven't been quiet long enough, defer.
|
|
1205
|
+
if (stillActive && !force) {
|
|
1206
|
+
const remaining = Math.max(0, TRACE_LINGER_AFTER_FINISH_MS - quietMs);
|
|
1207
|
+
scheduleIdleFlush(Math.max(remaining, 10));
|
|
1199
1208
|
return;
|
|
1200
1209
|
}
|
|
1210
|
+
if (stillActive && force) {
|
|
1211
|
+
// Allow forced flush after either linger window of silence or max guard.
|
|
1212
|
+
if (quietMs < TRACE_LINGER_AFTER_FINISH_MS && waitedFinish < ACTIVE_SPAN_FORCE_FLUSH_MS) {
|
|
1213
|
+
const remainingQuiet = TRACE_LINGER_AFTER_FINISH_MS - quietMs;
|
|
1214
|
+
const remainingGuard = ACTIVE_SPAN_FORCE_FLUSH_MS - waitedFinish;
|
|
1215
|
+
scheduleIdleFlush(Math.max(10, Math.min(remainingQuiet, remainingGuard)));
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1201
1219
|
flushed = true;
|
|
1202
1220
|
clearTimers();
|
|
1203
1221
|
try {
|
|
@@ -1273,6 +1291,7 @@ function reproMiddleware(cfg) {
|
|
|
1273
1291
|
};
|
|
1274
1292
|
const spanKey = normalizeSpanId(evt.spanId);
|
|
1275
1293
|
if (evt.type === 'enter') {
|
|
1294
|
+
lastEventAt = Date.now();
|
|
1276
1295
|
if (spanKey) {
|
|
1277
1296
|
activeSpans.add(spanKey);
|
|
1278
1297
|
}
|
|
@@ -1281,6 +1300,7 @@ function reproMiddleware(cfg) {
|
|
|
1281
1300
|
}
|
|
1282
1301
|
}
|
|
1283
1302
|
else if (evt.type === 'exit') {
|
|
1303
|
+
lastEventAt = Date.now();
|
|
1284
1304
|
if (spanKey && activeSpans.has(spanKey)) {
|
|
1285
1305
|
activeSpans.delete(spanKey);
|
|
1286
1306
|
}
|
|
@@ -1321,6 +1341,9 @@ function reproMiddleware(cfg) {
|
|
|
1321
1341
|
if (finished && flushed)
|
|
1322
1342
|
return;
|
|
1323
1343
|
finished = true;
|
|
1344
|
+
if (finishedAt === null) {
|
|
1345
|
+
finishedAt = Date.now();
|
|
1346
|
+
}
|
|
1324
1347
|
if (capturedBody === undefined && chunks.length) {
|
|
1325
1348
|
const buf = Buffer.isBuffer(chunks[0])
|
|
1326
1349
|
? Buffer.concat(chunks.map(c => (Buffer.isBuffer(c) ? c : Buffer.from(String(c)))))
|
|
@@ -1411,14 +1434,7 @@ function reproMiddleware(cfg) {
|
|
|
1411
1434
|
if (__TRACER_READY) {
|
|
1412
1435
|
bumpIdle();
|
|
1413
1436
|
const hardDeadlineMs = Math.max(TRACE_FLUSH_DELAY_MS + TRACE_LINGER_AFTER_FINISH_MS, TRACE_IDLE_FLUSH_MS + TRACE_FLUSH_DELAY_MS);
|
|
1414
|
-
hardStopTimer = setTimeout(() =>
|
|
1415
|
-
if (hasActiveWork()) {
|
|
1416
|
-
scheduleIdleFlush();
|
|
1417
|
-
hardStopTimer = setTimeout(() => doFlush(true), TRACE_LINGER_AFTER_FINISH_MS);
|
|
1418
|
-
return;
|
|
1419
|
-
}
|
|
1420
|
-
doFlush(true);
|
|
1421
|
-
}, hardDeadlineMs);
|
|
1437
|
+
hardStopTimer = setTimeout(() => doFlush(true), hardDeadlineMs);
|
|
1422
1438
|
}
|
|
1423
1439
|
else {
|
|
1424
1440
|
doFlush(true);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1372,12 +1372,15 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1372
1372
|
let unsubscribe: undefined | (() => void);
|
|
1373
1373
|
let flushed = false;
|
|
1374
1374
|
let finished = false;
|
|
1375
|
+
let finishedAt: number | null = null;
|
|
1376
|
+
let lastEventAt: number = Date.now();
|
|
1375
1377
|
let idleTimer: NodeJS.Timeout | null = null;
|
|
1376
1378
|
let hardStopTimer: NodeJS.Timeout | null = null;
|
|
1377
1379
|
let drainTimer: NodeJS.Timeout | null = null;
|
|
1378
1380
|
let flushPayload: null | (() => void) = null;
|
|
1379
1381
|
const activeSpans = new Set<string>();
|
|
1380
1382
|
let anonymousSpanDepth = 0;
|
|
1383
|
+
const ACTIVE_SPAN_FORCE_FLUSH_MS = 30000; // safety guard against leaks
|
|
1381
1384
|
|
|
1382
1385
|
const clearTimers = () => {
|
|
1383
1386
|
if (idleTimer) {
|
|
@@ -1396,21 +1399,37 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1396
1399
|
|
|
1397
1400
|
const hasActiveWork = () => activeSpans.size > 0 || anonymousSpanDepth > 0;
|
|
1398
1401
|
|
|
1399
|
-
const scheduleIdleFlush = () => {
|
|
1402
|
+
const scheduleIdleFlush = (delay: number = TRACE_IDLE_FLUSH_MS) => {
|
|
1400
1403
|
if (!finished || flushed) return;
|
|
1401
1404
|
if (hasActiveWork()) return;
|
|
1402
1405
|
if (idleTimer) {
|
|
1403
1406
|
try { clearTimeout(idleTimer); } catch {}
|
|
1404
1407
|
}
|
|
1405
|
-
idleTimer = setTimeout(() => doFlush(false),
|
|
1408
|
+
idleTimer = setTimeout(() => doFlush(false), delay);
|
|
1406
1409
|
};
|
|
1407
1410
|
|
|
1408
1411
|
const doFlush = (force: boolean = false) => {
|
|
1409
1412
|
if (flushed) return;
|
|
1410
|
-
|
|
1411
|
-
|
|
1413
|
+
const now = Date.now();
|
|
1414
|
+
const stillActive = hasActiveWork();
|
|
1415
|
+
const quietMs = now - lastEventAt;
|
|
1416
|
+
const waitedFinish = finishedAt === null ? 0 : now - finishedAt;
|
|
1417
|
+
|
|
1418
|
+
// If work is still active and we haven't been quiet long enough, defer.
|
|
1419
|
+
if (stillActive && !force) {
|
|
1420
|
+
const remaining = Math.max(0, TRACE_LINGER_AFTER_FINISH_MS - quietMs);
|
|
1421
|
+
scheduleIdleFlush(Math.max(remaining, 10));
|
|
1412
1422
|
return;
|
|
1413
1423
|
}
|
|
1424
|
+
if (stillActive && force) {
|
|
1425
|
+
// Allow forced flush after either linger window of silence or max guard.
|
|
1426
|
+
if (quietMs < TRACE_LINGER_AFTER_FINISH_MS && waitedFinish < ACTIVE_SPAN_FORCE_FLUSH_MS) {
|
|
1427
|
+
const remainingQuiet = TRACE_LINGER_AFTER_FINISH_MS - quietMs;
|
|
1428
|
+
const remainingGuard = ACTIVE_SPAN_FORCE_FLUSH_MS - waitedFinish;
|
|
1429
|
+
scheduleIdleFlush(Math.max(10, Math.min(remainingQuiet, remainingGuard)));
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1414
1433
|
flushed = true;
|
|
1415
1434
|
clearTimers();
|
|
1416
1435
|
try { unsubscribe && unsubscribe(); } catch {}
|
|
@@ -1482,12 +1501,14 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1482
1501
|
|
|
1483
1502
|
const spanKey = normalizeSpanId(evt.spanId);
|
|
1484
1503
|
if (evt.type === 'enter') {
|
|
1504
|
+
lastEventAt = Date.now();
|
|
1485
1505
|
if (spanKey) {
|
|
1486
1506
|
activeSpans.add(spanKey);
|
|
1487
1507
|
} else {
|
|
1488
1508
|
anonymousSpanDepth = Math.max(0, anonymousSpanDepth + 1);
|
|
1489
1509
|
}
|
|
1490
1510
|
} else if (evt.type === 'exit') {
|
|
1511
|
+
lastEventAt = Date.now();
|
|
1491
1512
|
if (spanKey && activeSpans.has(spanKey)) {
|
|
1492
1513
|
activeSpans.delete(spanKey);
|
|
1493
1514
|
} else if (!spanKey && anonymousSpanDepth > 0) {
|
|
@@ -1531,6 +1552,9 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1531
1552
|
const handleDone = () => {
|
|
1532
1553
|
if (finished && flushed) return;
|
|
1533
1554
|
finished = true;
|
|
1555
|
+
if (finishedAt === null) {
|
|
1556
|
+
finishedAt = Date.now();
|
|
1557
|
+
}
|
|
1534
1558
|
if (capturedBody === undefined && chunks.length) {
|
|
1535
1559
|
const buf = Buffer.isBuffer(chunks[0])
|
|
1536
1560
|
? Buffer.concat(chunks.map(c => (Buffer.isBuffer(c) ? c : Buffer.from(String(c)))))
|
|
@@ -1623,14 +1647,7 @@ export function reproMiddleware(cfg: ReproMiddlewareConfig) {
|
|
|
1623
1647
|
TRACE_FLUSH_DELAY_MS + TRACE_LINGER_AFTER_FINISH_MS,
|
|
1624
1648
|
TRACE_IDLE_FLUSH_MS + TRACE_FLUSH_DELAY_MS,
|
|
1625
1649
|
);
|
|
1626
|
-
hardStopTimer = setTimeout(() =>
|
|
1627
|
-
if (hasActiveWork()) {
|
|
1628
|
-
scheduleIdleFlush();
|
|
1629
|
-
hardStopTimer = setTimeout(() => doFlush(true), TRACE_LINGER_AFTER_FINISH_MS);
|
|
1630
|
-
return;
|
|
1631
|
-
}
|
|
1632
|
-
doFlush(true);
|
|
1633
|
-
}, hardDeadlineMs);
|
|
1650
|
+
hardStopTimer = setTimeout(() => doFlush(true), hardDeadlineMs);
|
|
1634
1651
|
} else {
|
|
1635
1652
|
doFlush(true);
|
|
1636
1653
|
}
|