faastjs
Version:
Serverless batch computing made simple.
139 lines • 14.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearLeakDetector = exports.onAsyncHook = exports.stopAsyncTracing = exports.printHooks = exports.detectAsyncLeaks = exports.printAsyncStack = exports.trace = exports.startAsyncTracing = void 0;
const tslib_1 = require("tslib");
const async_hooks_1 = tslib_1.__importDefault(require("async_hooks"));
const util_1 = require("util");
let hook;
const asyncObjects = new Map();
const objectMapping = new Map();
function startAsyncTracing(stackTraces = false) {
hook = onAsyncHook(stackTraces);
}
exports.startAsyncTracing = startAsyncTracing;
function trace(obj) {
let res = objectMapping.get(obj);
if (!res) {
// console.log(`trace: object not found: ${util.inspect(obj)}`);
return;
}
let asyncTrace = `== Tracing leaked object ${res.asyncId} ==`;
while (res) {
const { stack, ...rest } = res;
asyncTrace += `${(0, util_1.inspect)(rest)}\n${stack}`;
res = asyncObjects.get(res.triggerId);
}
console.log(asyncTrace);
return { obj, trace: asyncTrace };
}
exports.trace = trace;
function printAsyncStack() {
console.log(`Async stack:`);
let res = asyncObjects.get(async_hooks_1.default.executionAsyncId());
while (res) {
const { stack, ...rest } = res;
console.log(`%O\n${stack}`, rest);
res = asyncObjects.get(res.triggerId);
}
}
exports.printAsyncStack = printAsyncStack;
function detectAsyncLeaks() {
const leaks = [];
process._getActiveHandles().forEach((h) => {
if (h !== process.stdout && h !== process.stderr) {
const leak = trace(h);
leak && leaks.push(leak);
}
});
process._getActiveRequests().forEach((h) => {
const leak = trace(h);
leak && leaks.push(leak);
});
return leaks;
}
exports.detectAsyncLeaks = detectAsyncLeaks;
function printHooks() {
for (const obj of asyncObjects) {
console.log(`%O`, obj);
}
}
exports.printHooks = printHooks;
function stopAsyncTracing() {
hook?.();
}
exports.stopAsyncTracing = stopAsyncTracing;
function onAsyncHook(stackTraces) {
const hooks = {
init,
before,
after,
destroy,
promiseResolve
};
const asyncHook = async_hooks_1.default.createHook(hooks);
asyncHook.enable();
return () => {
asyncHook.disable();
};
function init(asyncId, type, triggerId, resource) {
const obj = {
asyncId,
type,
triggerId,
resource,
state: "init",
startedCount: 0,
finishedCount: 0,
stack: stackTraces
? new Error("stack:").stack.replace(/Error:/, "")
: undefined
};
asyncObjects.set(asyncId, obj);
objectMapping.set(resource, obj);
}
function destroy(asyncId) {
const obj = asyncObjects.get(asyncId);
if (obj) {
obj.state = "destroyed";
}
else {
// console.log(`destroyed: No obj ${asyncId}`);
}
}
function before(asyncId) {
const obj = asyncObjects.get(asyncId);
if (obj) {
obj.state = "before";
obj.startedCount++;
}
else {
// console.log(`before: No obj ${asyncId}`);
}
}
function after(asyncId) {
const obj = asyncObjects.get(asyncId);
if (obj) {
obj.state = "after";
obj.finishedCount++;
}
else {
// console.log(`after: No obj ${asyncId}`);
}
}
function promiseResolve(asyncId) {
const obj = asyncObjects.get(asyncId);
if (obj) {
obj.state = "resolved";
}
else {
// console.log(`resolved: No obj ${asyncId}`);
}
}
}
exports.onAsyncHook = onAsyncHook;
function clearLeakDetector() {
asyncObjects.clear();
objectMapping.clear();
}
exports.clearLeakDetector = clearLeakDetector;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLHNFQUFxQztBQUNyQywrQkFBK0I7QUFFL0IsSUFBSSxJQUE0QixDQUFDO0FBZWpDLE1BQU0sWUFBWSxHQUE2QixJQUFJLEdBQUcsRUFBRSxDQUFDO0FBQ3pELE1BQU0sYUFBYSxHQUE2QixJQUFJLEdBQUcsRUFBRSxDQUFDO0FBRTFELFNBQWdCLGlCQUFpQixDQUFDLGNBQXVCLEtBQUs7SUFDMUQsSUFBSSxHQUFHLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUNwQyxDQUFDO0FBRkQsOENBRUM7QUFPRCxTQUFnQixLQUFLLENBQUMsR0FBVztJQUM3QixJQUFJLEdBQUcsR0FBRyxhQUFhLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2pDLElBQUksQ0FBQyxHQUFHLEVBQUU7UUFDTixnRUFBZ0U7UUFDaEUsT0FBTztLQUNWO0lBQ0QsSUFBSSxVQUFVLEdBQUcsNEJBQTRCLEdBQUcsQ0FBQyxPQUFPLEtBQUssQ0FBQztJQUM5RCxPQUFPLEdBQUcsRUFBRTtRQUNSLE1BQU0sRUFBRSxLQUFLLEVBQUUsR0FBRyxJQUFJLEVBQUUsR0FBRyxHQUFHLENBQUM7UUFDL0IsVUFBVSxJQUFJLEdBQUcsSUFBQSxjQUFPLEVBQUMsSUFBSSxDQUFDLEtBQUssS0FBSyxFQUFFLENBQUM7UUFDM0MsR0FBRyxHQUFHLFlBQVksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0tBQ3pDO0lBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QixPQUFPLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsQ0FBQztBQUN0QyxDQUFDO0FBZEQsc0JBY0M7QUFFRCxTQUFnQixlQUFlO0lBQzNCLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENB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QUM7UUFDdEMsSUFBSSxHQUFHLEVBQUU7WUFDTCxHQUFHLENBQUMsS0FBSyxHQUFHLFdBQVcsQ0FBQztTQUMzQjthQUFNO1lBQ0gsK0NBQStDO1NBQ2xEO0lBQ0wsQ0FBQztJQUNELFNBQVMsTUFBTSxDQUFDLE9BQWU7UUFDM0IsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0QyxJQUFJLEdBQUcsRUFBRTtZQUNMLEdBQUcsQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDO1lBQ3JCLEdBQUcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztTQUN0QjthQUFNO1lBQ0gsNENBQTRDO1NBQy9DO0lBQ0wsQ0FBQztJQUNELFNBQVMsS0FBSyxDQUFDLE9BQWU7UUFDMUIsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0QyxJQUFJLEdBQUcsRUFBRTtZQUNMLEdBQUcsQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDO1lBQ3BCLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztTQUN2QjthQUFNO1lBQ0gsMkNBQTJDO1NBQzlDO0lBQ0wsQ0FBQztJQUNELFNBQVMsY0FBYyxDQUFDLE9BQWU7UUFDbkMsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0QyxJQUFJLEdBQUcsRUFBRTtZQUNMLEdBQUcsQ0FBQyxLQUFLLEdBQUcsVUFBVSxDQUFDO1NBQzFCO2FBQU07WUFDSCw4Q0FBOEM7U0FDakQ7SUFDTCxDQUFDO0FBQ0wsQ0FBQztBQWxFRCxrQ0FrRUM7QUFFRCxTQUFnQixpQkFBaUI7SUFDN0IsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3JCLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUMxQixDQUFDO0FBSEQsOENBR0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXN5bmNIb29rcyBmcm9tIFwiYXN5bmNfaG9va3NcIjtcbmltcG9ydCB7IGluc3BlY3QgfSBmcm9tIFwidXRpbFwiO1xuXG5sZXQgaG9vazogKCkgPT4gdm9pZCB8IHVuZGVmaW5lZDtcblxudHlwZSBBc3luY1N0YXRlID0gXCJpbml0XCIgfCBcImJlZm9yZVwiIHwgXCJhZnRlclwiIHwgXCJkZXN0cm95ZWRcIiB8IFwicmVzb2x2ZWRcIjtcblxuaW50ZXJmYWNlIEFzeW5jT2JqZWN0IHtcbiAgICBhc3luY0lkOiBudW1iZXI7XG4gICAgdHlwZTogc3RyaW5nO1xuICAgIHRyaWdnZXJJZDogbnVtYmVyO1xuICAgIHJlc291cmNlOiBhbnk7XG4gICAgc3RhdGU6IEFzeW5jU3RhdGU7XG4gICAgc3RhcnRlZENvdW50OiBudW1iZXI7XG4gICAgZmluaXNoZWRDb3VudDogbnVtYmVyO1xuICAgIHN0YWNrPzogc3RyaW5nO1xufVxuXG5jb25zdCBhc3luY09iamVjdHM6IE1hcDxudW1iZXIsIEFzeW5jT2JqZWN0PiA9IG5ldyBNYXAoKTtcbmNvbnN0IG9iamVjdE1hcHBpbmc6IE1hcDxvYmplY3QsIEFzeW5jT2JqZWN0PiA9IG5ldyBNYXAoKTtcblxuZXhwb3J0IGZ1bmN0aW9uIHN0YXJ0QXN5bmNUcmFjaW5nKHN0YWNrVHJhY2VzOiBib29sZWFuID0gZmFsc2UpIHtcbiAgICBob29rID0gb25Bc3luY0hvb2soc3RhY2tUcmFjZXMpO1xufVxuXG5pbnRlcmZhY2UgVHJhY2Uge1xuICAgIG9iajogb2JqZWN0O1xuICAgIHRyYWNlOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0cmFjZShvYmo6IG9iamVjdCk6IFRyYWNlIHwgdm9pZCB7XG4gICAgbGV0IHJlcyA9IG9iamVjdE1hcHBpbmcuZ2V0KG9iaik7XG4gICAgaWYgKCFyZXMpIHtcbiAgICAgICAgLy8gY29uc29sZS5sb2coYHRyYWNlOiBvYmplY3Qgbm90IGZvdW5kOiAke3V0aWwuaW5zcGVjdChvYmopfWApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBhc3luY1RyYWNlID0gYD09IFRyYWNpbmcgbGVha2VkIG9iamVjdCAke3Jlcy5hc3luY0lkfSA9PWA7XG4gICAgd2hpbGUgKHJlcykge1xuICAgICAgICBjb25zdCB7IHN0YWNrLCAuLi5yZXN0IH0gPSByZXM7XG4gICAgICAgIGFzeW5jVHJhY2UgKz0gYCR7aW5zcGVjdChyZXN0KX1cXG4ke3N0YWNrfWA7XG4gICAgICAgIHJlcyA9IGFzeW5jT2JqZWN0cy5nZXQocmVzLnRyaWdnZXJJZCk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKGFzeW5jVHJhY2UpO1xuICAgIHJldHVybiB7IG9iaiwgdHJhY2U6IGFzeW5jVHJhY2UgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHByaW50QXN5bmNTdGFjaygpIHtcbiAgICBjb25zb2xlLmxvZyhgQXN5bmMgc3RhY2s6YCk7XG4gICAgbGV0IHJlcyA9IGFzeW5jT2JqZWN0cy5nZXQoYXN5bmNIb29rcy5leGVjdXRpb25Bc3luY0lkKCkpO1xuICAgIHdoaWxlIChyZXMpIHtcbiAgICAgICAgY29uc3QgeyBzdGFjaywgLi4ucmVzdCB9ID0gcmVzO1xuICAgICAgICBjb25zb2xlLmxvZyhgJU9cXG4ke3N0YWNrfWAsIHJlc3QpO1xuICAgICAgICByZXMgPSBhc3luY09iamVjdHMuZ2V0KHJlcy50cmlnZ2VySWQpO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRldGVjdEFzeW5jTGVha3MoKTogb2JqZWN0W10ge1xuICAgIGNvbnN0IGxlYWtzOiBUcmFjZVtdID0gW107XG4gICAgKHByb2Nlc3MgYXMgYW55KS5fZ2V0QWN0aXZlSGFuZGxlcygpLmZvckVhY2goKGg6IG9iamVjdCkgPT4ge1xuICAgICAgICBpZiAoaCAhPT0gcHJvY2Vzcy5zdGRvdXQgJiYgaCAhPT0gcHJvY2Vzcy5zdGRlcnIpIHtcbiAgICAgICAgICAgIGNvbnN0IGxlYWsgPSB0cmFjZShoKTtcbiAgICAgICAgICAgIGxlYWsgJiYgbGVha3MucHVzaChsZWFrKTtcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIChwcm9jZXNzIGFzIGFueSkuX2dldEFjdGl2ZVJlcXVlc3RzKCkuZm9yRWFjaCgoaDogb2JqZWN0KSA9PiB7XG4gICAgICAgIGNvbnN0IGxlYWsgPSB0cmFjZShoKTtcbiAgICAgICAgbGVhayAmJiBsZWFrcy5wdXNoKGxlYWspO1xuICAgIH0pO1xuICAgIHJldHVybiBsZWFrcztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHByaW50SG9va3MoKSB7XG4gICAgZm9yIChjb25zdCBvYmogb2YgYXN5bmNPYmplY3RzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAlT2AsIG9iaik7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gc3RvcEFzeW5jVHJhY2luZygpIHtcbiAgICBob29rPy4oKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG9uQXN5bmNIb29rKHN0YWNrVHJhY2VzOiBib29sZWFuKSB7XG4gICAgY29uc3QgaG9va3M6IGFzeW5jSG9va3MuSG9va0NhbGxiYWNrcyA9IHtcbiAgICAgICAgaW5pdCxcbiAgICAgICAgYmVmb3JlLFxuICAgICAgICBhZnRlcixcbiAgICAgICAgZGVzdHJveSxcbiAgICAgICAgcHJvbWlzZVJlc29sdmVcbiAgICB9O1xuXG4gICAgY29uc3QgYXN5bmNIb29rID0gYXN5bmNIb29rcy5jcmVhdGVIb29rKGhvb2tzKTtcbiAgICBhc3luY0hvb2suZW5hYmxlKCk7XG5cbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBhc3luY0hvb2suZGlzYWJsZSgpO1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBpbml0KGFzeW5jSWQ6IG51bWJlciwgdHlwZTogc3RyaW5nLCB0cmlnZ2VySWQ6IG51bWJlciwgcmVzb3VyY2U6IG9iamVjdCkge1xuICAgICAgICBjb25zdCBvYmo6IEFzeW5jT2JqZWN0ID0ge1xuICAgICAgICAgICAgYXN5bmNJZCxcbiAgICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgICB0cmlnZ2VySWQsXG4gICAgICAgICAgICByZXNvdXJjZSxcbiAgICAgICAgICAgIHN0YXRlOiBcImluaXRcIixcbiAgICAgICAgICAgIHN0YXJ0ZWRDb3VudDogMCxcbiAgICAgICAgICAgIGZpbmlzaGVkQ291bnQ6IDAsXG4gICAgICAgICAgICBzdGFjazogc3RhY2tUcmFjZXNcbiAgICAgICAgICAgICAgICA/IG5ldyBFcnJvcihcInN0YWNrOlwiKS5zdGFjayEucmVwbGFjZSgvRXJyb3I6LywgXCJcIilcbiAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZFxuICAgICAgICB9O1xuICAgICAgICBhc3luY09iamVjdHMuc2V0KGFzeW5jSWQsIG9iaik7XG4gICAgICAgIG9iamVjdE1hcHBpbmcuc2V0KHJlc291cmNlLCBvYmopO1xuICAgIH1cbiAgICBmdW5jdGlvbiBkZXN0cm95KGFzeW5jSWQ6IG51bWJlcikge1xuICAgICAgICBjb25zdCBvYmogPSBhc3luY09iamVjdHMuZ2V0KGFzeW5jSWQpO1xuICAgICAgICBpZiAob2JqKSB7XG4gICAgICAgICAgICBvYmouc3RhdGUgPSBcImRlc3Ryb3llZFwiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coYGRlc3Ryb3llZDogTm8gb2JqICR7YXN5bmNJZH1gKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBmdW5jdGlvbiBiZWZvcmUoYXN5bmNJZDogbnVtYmVyKSB7XG4gICAgICAgIGNvbnN0IG9iaiA9IGFzeW5jT2JqZWN0cy5nZXQoYXN5bmNJZCk7XG4gICAgICAgIGlmIChvYmopIHtcbiAgICAgICAgICAgIG9iai5zdGF0ZSA9IFwiYmVmb3JlXCI7XG4gICAgICAgICAgICBvYmouc3RhcnRlZENvdW50Kys7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhgYmVmb3JlOiBObyBvYmogJHthc3luY0lkfWApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZ1bmN0aW9uIGFmdGVyKGFzeW5jSWQ6IG51bWJlcikge1xuICAgICAgICBjb25zdCBvYmogPSBhc3luY09iamVjdHMuZ2V0KGFzeW5jSWQpO1xuICAgICAgICBpZiAob2JqKSB7XG4gICAgICAgICAgICBvYmouc3RhdGUgPSBcImFmdGVyXCI7XG4gICAgICAgICAgICBvYmouZmluaXNoZWRDb3VudCsrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coYGFmdGVyOiBObyBvYmogJHthc3luY0lkfWApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZ1bmN0aW9uIHByb21pc2VSZXNvbHZlKGFzeW5jSWQ6IG51bWJlcikge1xuICAgICAgICBjb25zdCBvYmogPSBhc3luY09iamVjdHMuZ2V0KGFzeW5jSWQpO1xuICAgICAgICBpZiAob2JqKSB7XG4gICAgICAgICAgICBvYmouc3RhdGUgPSBcInJlc29sdmVkXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhgcmVzb2x2ZWQ6IE5vIG9iaiAke2FzeW5jSWR9YCk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjbGVhckxlYWtEZXRlY3RvcigpIHtcbiAgICBhc3luY09iamVjdHMuY2xlYXIoKTtcbiAgICBvYmplY3RNYXBwaW5nLmNsZWFyKCk7XG59XG4iXX0=