-
Notifications
You must be signed in to change notification settings - Fork 0
/
async-interceptor.js
45 lines (34 loc) · 1.08 KB
/
async-interceptor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import async_hooks from 'node:async_hooks';
// 50% of map limit
export const GC_LIMIT = Meteor.isPackageTest ? 7 : Math.pow(2, 23);
export const AsyncResourceMap = new Map();
export const AsyncInterceptor = async_hooks.createHook({
init(asyncId, type) {
captureResource(asyncId, type);
},
});
function captureResource(asyncId, type) {
let stack = stackTrace();
stack = `${type}\n${stack}`;
if (AsyncResourceMap.size > GC_LIMIT) {
garbageCollectAsyncResources();
}
if (!AsyncResourceMap.has(stack)) {
AsyncResourceMap.set(stack, { count: 0, ts: Date.now() });
}
const resourceInfo = AsyncResourceMap.get(stack);
resourceInfo.count++;
}
function garbageCollectAsyncResources() {
AsyncResourceMap.forEach((info, stack) => {
if (info.count <= 1) {
AsyncResourceMap.delete(stack);
}
});
}
export function stackTrace () {
return (new Error()).stack.split('\n').slice(3).filter(line => {
return !['AsyncHook.init', 'node:internal/async_hooks'].some(fn => line.includes(fn));
}).join('\n')
}
setInterval(garbageCollectAsyncResources, 10000);