/** * The `async_hooks` module provides an API to track asynchronous resources. It * can be accessed using: * * ```js * import async_hooks from 'async_hooks'; * ``` * @experimental * @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/async_hooks.js) */ declare module 'async_hooks' { /** * ```js * import { executionAsyncId } from 'async_hooks'; * * console.log(executionAsyncId()); // 1 - bootstrap * fs.open(path, 'r', (err, fd) => { * console.log(executionAsyncId()); // 6 - open() * }); * ``` * * The ID returned from `executionAsyncId()` is related to execution timing, not * causality (which is covered by `triggerAsyncId()`): * * ```js * const server = net.createServer((conn) => { * // Returns the ID of the server, not of the new connection, because the * // callback runs in the execution scope of the server's MakeCallback(). * async_hooks.executionAsyncId(); * * }).listen(port, () => { * // Returns the ID of a TickObject (process.nextTick()) because all * // callbacks passed to .listen() are wrapped in a nextTick(). * async_hooks.executionAsyncId(); * }); * ``` * * Promise contexts may not get precise `executionAsyncIds` by default. * See the section on `promise execution tracking`. * @since v8.1.0 * @return The `asyncId` of the current execution context. Useful to track when something calls. */ function executionAsyncId(): number; /** * Resource objects returned by `executionAsyncResource()` are most often internal * Node.js handle objects with undocumented APIs. Using any functions or properties * on the object is likely to crash your application and should be avoided. * * Using `executionAsyncResource()` in the top-level execution context will * return an empty object as there is no handle or request object to use, * but having an object representing the top-level can be helpful. * * ```js * import { open } from 'fs'; * import { executionAsyncId, executionAsyncResource } from 'async_hooks'; * * console.log(executionAsyncId(), executionAsyncResource()); // 1 {} * open(new URL(import.meta.url), 'r', (err, fd) => { * console.log(executionAsyncId(), executionAsyncResource()); // 7 FSReqWrap * }); * ``` * * This can be used to implement continuation local storage without the * use of a tracking `Map` to store the metadata: * * ```js * import { createServer } from 'http'; * import { * executionAsyncId, * executionAsyncResource, * createHook * } from 'async_hooks'; * const sym = Symbol('state'); // Private symbol to avoid pollution * * createHook({ * init(asyncId, type, triggerAsyncId, resource) { * const cr = executionAsyncResource(); * if (cr) { * resource[sym] = cr[sym]; * } * } * }).enable(); * * const server = createServer((req, res) => { * executionAsyncResource()[sym] = { state: req.url }; * setTimeout(function() { * res.end(JSON.stringify(executionAsyncResource()[sym])); * }, 100); * }).listen(3000); * ``` * @since v13.9.0, v12.17.0 * @return The resource representing the current execution. Useful to store data within the resource. */ function executionAsyncResource(): object; /** * ```js * const server = net.createServer((conn) => { * // The resource that caused (or triggered) this callback to be called * // was that of the new connection. Thus the return value of triggerAsyncId() * // is the asyncId of "conn". * async_hooks.triggerAsyncId(); * * }).listen(port, () => { * // Even though all callbacks passed to .listen() are wrapped in a nextTick() * // the callback itself exists because the call to the server's .listen() * // was made. So the return value would be the ID of the server. * async_hooks.triggerAsyncId(); * }); * ``` * * Promise contexts may not get valid `triggerAsyncId`s by default. See * the section on `promise execution tracking`. * @return The ID of the resource responsible for calling the callback that is currently being executed. */ function triggerAsyncId(): number; interface HookCallbacks { /** * Called when a class is constructed that has the possibility to emit an asynchronous event. * @param asyncId a unique ID for the async resource * @param type the type of the async resource * @param triggerAsyncId the unique ID of the async resource in whose execution context this async resource was created * @param resource reference to the resource representing the async operation, needs to be released during destroy */ init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void; /** * When an asynchronous operation is initiated or completes a callback is called to notify the user. * The before callback is called just before said callback is executed. * @param asyncId the unique identifier assigned to the resource about to execute the callback. */ before?(asyncId: number): void; /** * Called immediately after the callback specified in before is completed. * @param asyncId the unique identifier assigned to the resource which has executed the callback. */ after?(asyncId: number): void; /** * Called when a promise has resolve() called. This may not be in the same execution id * as the promise itself. * @param asyncId the unique id for the promise that was resolve()d. */ promiseResolve?(asyncId: number): void; /** * Called after the resource corresponding to asyncId is destroyed * @param asyncId a unique ID for the async resource */ destroy?(asyncId: number): void; } interface AsyncHook { /** * Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop. */ enable(): this; /** * Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled. */ disable(): this; } /** * Registers functions to be called for different lifetime events of each async * operation. * * The callbacks `init()`/`before()`/`after()`/`destroy()` are called for the * respective asynchronous event during a resource's lifetime. * * All callbacks are optional. For example, if only resource cleanup needs to * be tracked, then only the `destroy` callback needs to be passed. The * specifics of all functions that can be passed to `callbacks` is in the `Hook Callbacks` section. * * ```js * import { createHook } from 'async_hooks'; * * const asyncHook = createHook({ * init(asyncId, type, triggerAsyncId, resource) { }, * destroy(asyncId) { } * }); * ``` * * The callbacks will be inherited via the prototype chain: * * ```js * class MyAsyncCallbacks { * init(asyncId, type, triggerAsyncId, resource) { } * destroy(asyncId) {} * } * * class MyAddedCallbacks extends MyAsyncCallbacks { * before(asyncId) { } * after(asyncId) { } * } * * const asyncHook = async_hooks.createHook(new MyAddedCallbacks()); * ``` * * Because promises are asynchronous resources whose lifecycle is tracked * via the async hooks mechanism, the `init()`, `before()`, `after()`, and`destroy()` callbacks _must not_ be async functions that return promises. * @since v8.1.0 * @param callbacks The `Hook Callbacks` to register * @return Instance used for disabling and enabling hooks */ function createHook(callbacks: HookCallbacks): AsyncHook; interface AsyncResourceOptions { /** * The ID of the execution context that created this async event. * @default executionAsyncId() */ triggerAsyncId?: number | undefined; /** * Disables automatic `emitDestroy` when the object is garbage collected. * This usually does not need to be set (even if `emitDestroy` is called * manually), unless the resource's `asyncId` is retrieved and the * sensitive API's `emitDestroy` is called with it. * @default false */ requireManualDestroy?: boolean | undefined; } /** * The class `AsyncResource` is designed to be extended by the embedder's async * resources. Using this, users can easily trigger the lifetime events of their * own resources. * * The `init` hook will trigger when an `AsyncResource` is instantiated. * * The following is an overview of the `AsyncResource` API. * * ```js * import { AsyncResource, executionAsyncId } from 'async_hooks'; * * // AsyncResource() is meant to be extended. Instantiating a * // new AsyncResource() also triggers init. If triggerAsyncId is omitted then * // async_hook.executionAsyncId() is used. * const asyncResource = new AsyncResource( * type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false } * ); * * // Run a function in the execution context of the resource. This will * // * establish the context of the resource * // * trigger the AsyncHooks before callbacks * // * call the provided function `fn` with the supplied arguments * // * trigger the AsyncHooks after callbacks * // * restore the original execution context * asyncResource.runInAsyncScope(fn, thisArg, ...args); * * // Call AsyncHooks destroy callbacks. * asyncResource.emitDestroy(); * * // Return the unique ID assigned to the AsyncResource instance. * asyncResource.asyncId(); * * // Return the trigger ID for the AsyncResource instance. * asyncResource.triggerAsyncId(); * ``` */ class AsyncResource { /** * AsyncResource() is meant to be extended. Instantiating a * new AsyncResource() also triggers init. If triggerAsyncId is omitted then * async_hook.executionAsyncId() is used. * @param type The type of async event. * @param triggerAsyncId The ID of the execution context that created * this async event (default: `executionAsyncId()`), or an * AsyncResourceOptions object (since v9.3.0) */ constructor(type: string, triggerAsyncId?: number | AsyncResourceOptions); /** * Binds the given function to the current execution context. * * The returned function will have an `asyncResource` property referencing * the `AsyncResource` to which the function is bound. * @since v14.8.0, v12.19.0 * @param fn The function to bind to the current execution context. * @param type An optional name to associate with the underlying `AsyncResource`. */ static bind any, ThisArg>( fn: Func, type?: string, thisArg?: ThisArg ): Func & { asyncResource: AsyncResource; }; /** * Binds the given function to execute to this `AsyncResource`'s scope. * * The returned function will have an `asyncResource` property referencing * the `AsyncResource` to which the function is bound. * @since v14.8.0, v12.19.0 * @param fn The function to bind to the current `AsyncResource`. */ bind any>( fn: Func ): Func & { asyncResource: AsyncResource; }; /** * Call the provided function with the provided arguments in the execution context * of the async resource. This will establish the context, trigger the AsyncHooks * before callbacks, call the function, trigger the AsyncHooks after callbacks, and * then restore the original execution context. * @since v9.6.0 * @param fn The function to call in the execution context of this async resource. * @param thisArg The receiver to be used for the function call. * @param args Optional arguments to pass to the function. */ runInAsyncScope(fn: (this: This, ...args: any[]) => Result, thisArg?: This, ...args: any[]): Result; /** * Call all `destroy` hooks. This should only ever be called once. An error will * be thrown if it is called more than once. This **must** be manually called. If * the resource is left to be collected by the GC then the `destroy` hooks will * never be called. * @return A reference to `asyncResource`. */ emitDestroy(): this; /** * @return The unique `asyncId` assigned to the resource. */ asyncId(): number; /** * * @return The same `triggerAsyncId` that is passed to the `AsyncResource` constructor. */ triggerAsyncId(): number; } /** * This class creates stores that stay coherent through asynchronous operations. * * While you can create your own implementation on top of the `async_hooks` module,`AsyncLocalStorage` should be preferred as it is a performant and memory safe * implementation that involves significant optimizations that are non-obvious to * implement. * * The following example uses `AsyncLocalStorage` to build a simple logger * that assigns IDs to incoming HTTP requests and includes them in messages * logged within each request. * * ```js * import http from 'http'; * import { AsyncLocalStorage } from 'async_hooks'; * * const asyncLocalStorage = new AsyncLocalStorage(); * * function logWithId(msg) { * const id = asyncLocalStorage.getStore(); * console.log(`${id !== undefined ? id : '-'}:`, msg); * } * * let idSeq = 0; * http.createServer((req, res) => { * asyncLocalStorage.run(idSeq++, () => { * logWithId('start'); * // Imagine any chain of async operations here * setImmediate(() => { * logWithId('finish'); * res.end(); * }); * }); * }).listen(8080); * * http.get('http://localhost:8080'); * http.get('http://localhost:8080'); * // Prints: * // 0: start * // 1: start * // 0: finish * // 1: finish * ``` * * Each instance of `AsyncLocalStorage` maintains an independent storage context. * Multiple instances can safely exist simultaneously without risk of interfering * with each other's data. * @since v13.10.0, v12.17.0 */ class AsyncLocalStorage { /** * Disables the instance of `AsyncLocalStorage`. All subsequent calls * to `asyncLocalStorage.getStore()` will return `undefined` until`asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()` is called again. * * When calling `asyncLocalStorage.disable()`, all current contexts linked to the * instance will be exited. * * Calling `asyncLocalStorage.disable()` is required before the`asyncLocalStorage` can be garbage collected. This does not apply to stores * provided by the `asyncLocalStorage`, as those objects are garbage collected * along with the corresponding async resources. * * Use this method when the `asyncLocalStorage` is not in use anymore * in the current process. * @since v13.10.0, v12.17.0 * @experimental */ disable(): void; /** * Returns the current store. * If called outside of an asynchronous context initialized by * calling `asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()`, it * returns `undefined`. * @since v13.10.0, v12.17.0 */ getStore(): T | undefined; /** * Runs a function synchronously within a context and returns its * return value. The store is not accessible outside of the callback function. * The store is accessible to any asynchronous operations created within the * callback. * * The optional `args` are passed to the callback function. * * If the callback function throws an error, the error is thrown by `run()` too. * The stacktrace is not impacted by this call and the context is exited. * * Example: * * ```js * const store = { id: 2 }; * try { * asyncLocalStorage.run(store, () => { * asyncLocalStorage.getStore(); // Returns the store object * setTimeout(() => { * asyncLocalStorage.getStore(); // Returns the store object * }, 200); * throw new Error(); * }); * } catch (e) { * asyncLocalStorage.getStore(); // Returns undefined * // The error will be caught here * } * ``` * @since v13.10.0, v12.17.0 */ run(store: T, callback: (...args: TArgs) => R, ...args: TArgs): R; /** * Runs a function synchronously outside of a context and returns its * return value. The store is not accessible within the callback function or * the asynchronous operations created within the callback. Any `getStore()`call done within the callback function will always return `undefined`. * * The optional `args` are passed to the callback function. * * If the callback function throws an error, the error is thrown by `exit()` too. * The stacktrace is not impacted by this call and the context is re-entered. * * Example: * * ```js * // Within a call to run * try { * asyncLocalStorage.getStore(); // Returns the store object or value * asyncLocalStorage.exit(() => { * asyncLocalStorage.getStore(); // Returns undefined * throw new Error(); * }); * } catch (e) { * asyncLocalStorage.getStore(); // Returns the same object or value * // The error will be caught here * } * ``` * @since v13.10.0, v12.17.0 * @experimental */ exit(callback: (...args: TArgs) => R, ...args: TArgs): R; /** * Transitions into the context for the remainder of the current * synchronous execution and then persists the store through any following * asynchronous calls. * * Example: * * ```js * const store = { id: 1 }; * // Replaces previous store with the given store object * asyncLocalStorage.enterWith(store); * asyncLocalStorage.getStore(); // Returns the store object * someAsyncOperation(() => { * asyncLocalStorage.getStore(); // Returns the same object * }); * ``` * * This transition will continue for the _entire_ synchronous execution. * This means that if, for example, the context is entered within an event * handler subsequent event handlers will also run within that context unless * specifically bound to another context with an `AsyncResource`. That is why`run()` should be preferred over `enterWith()` unless there are strong reasons * to use the latter method. * * ```js * const store = { id: 1 }; * * emitter.on('my-event', () => { * asyncLocalStorage.enterWith(store); * }); * emitter.on('my-event', () => { * asyncLocalStorage.getStore(); // Returns the same object * }); * * asyncLocalStorage.getStore(); // Returns undefined * emitter.emit('my-event'); * asyncLocalStorage.getStore(); // Returns the same object * ``` * @since v13.11.0, v12.17.0 * @experimental */ enterWith(store: T): void; } } declare module 'node:async_hooks' { export * from 'async_hooks'; }