UNPKG

faastjs

Version:

Serverless batch computing made simple.

139 lines 14.4 kB
"use strict"; 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=