UNPKG

20.8 kBTypeScriptView Raw
1/**
2 * The `async_hooks` module provides an API to track asynchronous resources. It
3 * can be accessed using:
4 *
5 * ```js
6 * const async_hooks = require('async_hooks');
7 * ```
8 * @experimental
9 * @see [source](https://github.com/nodejs/node/blob/v16.4.2/lib/async_hooks.js)
10 */
11declare module 'async_hooks' {
12 /**
13 * ```js
14 * const async_hooks = require('async_hooks');
15 *
16 * console.log(async_hooks.executionAsyncId()); // 1 - bootstrap
17 * fs.open(path, 'r', (err, fd) => {
18 * console.log(async_hooks.executionAsyncId()); // 6 - open()
19 * });
20 * ```
21 *
22 * The ID returned from `executionAsyncId()` is related to execution timing, not
23 * causality (which is covered by `triggerAsyncId()`):
24 *
25 * ```js
26 * const server = net.createServer((conn) => {
27 * // Returns the ID of the server, not of the new connection, because the
28 * // callback runs in the execution scope of the server's MakeCallback().
29 * async_hooks.executionAsyncId();
30 *
31 * }).listen(port, () => {
32 * // Returns the ID of a TickObject (process.nextTick()) because all
33 * // callbacks passed to .listen() are wrapped in a nextTick().
34 * async_hooks.executionAsyncId();
35 * });
36 * ```
37 *
38 * Promise contexts may not get precise `executionAsyncIds` by default.
39 * See the section on `promise execution tracking`.
40 * @since v8.1.0
41 * @return The `asyncId` of the current execution context. Useful to track when something calls.
42 */
43 function executionAsyncId(): number;
44 /**
45 * Resource objects returned by `executionAsyncResource()` are most often internal
46 * Node.js handle objects with undocumented APIs. Using any functions or properties
47 * on the object is likely to crash your application and should be avoided.
48 *
49 * Using `executionAsyncResource()` in the top-level execution context will
50 * return an empty object as there is no handle or request object to use,
51 * but having an object representing the top-level can be helpful.
52 *
53 * ```js
54 * const { open } = require('fs');
55 * const { executionAsyncId, executionAsyncResource } = require('async_hooks');
56 *
57 * console.log(executionAsyncId(), executionAsyncResource()); // 1 {}
58 * open(__filename, 'r', (err, fd) => {
59 * console.log(executionAsyncId(), executionAsyncResource()); // 7 FSReqWrap
60 * });
61 * ```
62 *
63 * This can be used to implement continuation local storage without the
64 * use of a tracking `Map` to store the metadata:
65 *
66 * ```js
67 * const { createServer } = require('http');
68 * const {
69 * executionAsyncId,
70 * executionAsyncResource,
71 * createHook
72 * } = require('async_hooks');
73 * const sym = Symbol('state'); // Private symbol to avoid pollution
74 *
75 * createHook({
76 * init(asyncId, type, triggerAsyncId, resource) {
77 * const cr = executionAsyncResource();
78 * if (cr) {
79 * resource[sym] = cr[sym];
80 * }
81 * }
82 * }).enable();
83 *
84 * const server = createServer((req, res) => {
85 * executionAsyncResource()[sym] = { state: req.url };
86 * setTimeout(function() {
87 * res.end(JSON.stringify(executionAsyncResource()[sym]));
88 * }, 100);
89 * }).listen(3000);
90 * ```
91 * @since v13.9.0, v12.17.0
92 * @return The resource representing the current execution. Useful to store data within the resource.
93 */
94 function executionAsyncResource(): object;
95 /**
96 * ```js
97 * const server = net.createServer((conn) => {
98 * // The resource that caused (or triggered) this callback to be called
99 * // was that of the new connection. Thus the return value of triggerAsyncId()
100 * // is the asyncId of "conn".
101 * async_hooks.triggerAsyncId();
102 *
103 * }).listen(port, () => {
104 * // Even though all callbacks passed to .listen() are wrapped in a nextTick()
105 * // the callback itself exists because the call to the server's .listen()
106 * // was made. So the return value would be the ID of the server.
107 * async_hooks.triggerAsyncId();
108 * });
109 * ```
110 *
111 * Promise contexts may not get valid `triggerAsyncId`s by default. See
112 * the section on `promise execution tracking`.
113 * @return The ID of the resource responsible for calling the callback that is currently being executed.
114 */
115 function triggerAsyncId(): number;
116 interface HookCallbacks {
117 /**
118 * Called when a class is constructed that has the possibility to emit an asynchronous event.
119 * @param asyncId a unique ID for the async resource
120 * @param type the type of the async resource
121 * @param triggerAsyncId the unique ID of the async resource in whose execution context this async resource was created
122 * @param resource reference to the resource representing the async operation, needs to be released during destroy
123 */
124 init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void;
125 /**
126 * When an asynchronous operation is initiated or completes a callback is called to notify the user.
127 * The before callback is called just before said callback is executed.
128 * @param asyncId the unique identifier assigned to the resource about to execute the callback.
129 */
130 before?(asyncId: number): void;
131 /**
132 * Called immediately after the callback specified in before is completed.
133 * @param asyncId the unique identifier assigned to the resource which has executed the callback.
134 */
135 after?(asyncId: number): void;
136 /**
137 * Called when a promise has resolve() called. This may not be in the same execution id
138 * as the promise itself.
139 * @param asyncId the unique id for the promise that was resolve()d.
140 */
141 promiseResolve?(asyncId: number): void;
142 /**
143 * Called after the resource corresponding to asyncId is destroyed
144 * @param asyncId a unique ID for the async resource
145 */
146 destroy?(asyncId: number): void;
147 }
148 interface AsyncHook {
149 /**
150 * Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop.
151 */
152 enable(): this;
153 /**
154 * 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.
155 */
156 disable(): this;
157 }
158 /**
159 * Registers functions to be called for different lifetime events of each async
160 * operation.
161 *
162 * The callbacks `init()`/`before()`/`after()`/`destroy()` are called for the
163 * respective asynchronous event during a resource's lifetime.
164 *
165 * All callbacks are optional. For example, if only resource cleanup needs to
166 * be tracked, then only the `destroy` callback needs to be passed. The
167 * specifics of all functions that can be passed to `callbacks` is in the `Hook Callbacks` section.
168 *
169 * ```js
170 * const async_hooks = require('async_hooks');
171 *
172 * const asyncHook = async_hooks.createHook({
173 * init(asyncId, type, triggerAsyncId, resource) { },
174 * destroy(asyncId) { }
175 * });
176 * ```
177 *
178 * The callbacks will be inherited via the prototype chain:
179 *
180 * ```js
181 * class MyAsyncCallbacks {
182 * init(asyncId, type, triggerAsyncId, resource) { }
183 * destroy(asyncId) {}
184 * }
185 *
186 * class MyAddedCallbacks extends MyAsyncCallbacks {
187 * before(asyncId) { }
188 * after(asyncId) { }
189 * }
190 *
191 * const asyncHook = async_hooks.createHook(new MyAddedCallbacks());
192 * ```
193 *
194 * Because promises are asynchronous resources whose lifecycle is tracked
195 * via the async hooks mechanism, the `init()`, `before()`, `after()`, and`destroy()` callbacks _must not_ be async functions that return promises.
196 * @since v8.1.0
197 * @param callbacks The `Hook Callbacks` to register
198 * @return Instance used for disabling and enabling hooks
199 */
200 function createHook(callbacks: HookCallbacks): AsyncHook;
201 interface AsyncResourceOptions {
202 /**
203 * The ID of the execution context that created this async event.
204 * @default executionAsyncId()
205 */
206 triggerAsyncId?: number | undefined;
207 /**
208 * Disables automatic `emitDestroy` when the object is garbage collected.
209 * This usually does not need to be set (even if `emitDestroy` is called
210 * manually), unless the resource's `asyncId` is retrieved and the
211 * sensitive API's `emitDestroy` is called with it.
212 * @default false
213 */
214 requireManualDestroy?: boolean | undefined;
215 }
216 /**
217 * The class `AsyncResource` is designed to be extended by the embedder's async
218 * resources. Using this, users can easily trigger the lifetime events of their
219 * own resources.
220 *
221 * The `init` hook will trigger when an `AsyncResource` is instantiated.
222 *
223 * The following is an overview of the `AsyncResource` API.
224 *
225 * ```js
226 * const { AsyncResource, executionAsyncId } = require('async_hooks');
227 *
228 * // AsyncResource() is meant to be extended. Instantiating a
229 * // new AsyncResource() also triggers init. If triggerAsyncId is omitted then
230 * // async_hook.executionAsyncId() is used.
231 * const asyncResource = new AsyncResource(
232 * type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false }
233 * );
234 *
235 * // Run a function in the execution context of the resource. This will
236 * // * establish the context of the resource
237 * // * trigger the AsyncHooks before callbacks
238 * // * call the provided function `fn` with the supplied arguments
239 * // * trigger the AsyncHooks after callbacks
240 * // * restore the original execution context
241 * asyncResource.runInAsyncScope(fn, thisArg, ...args);
242 *
243 * // Call AsyncHooks destroy callbacks.
244 * asyncResource.emitDestroy();
245 *
246 * // Return the unique ID assigned to the AsyncResource instance.
247 * asyncResource.asyncId();
248 *
249 * // Return the trigger ID for the AsyncResource instance.
250 * asyncResource.triggerAsyncId();
251 * ```
252 */
253 class AsyncResource {
254 /**
255 * AsyncResource() is meant to be extended. Instantiating a
256 * new AsyncResource() also triggers init. If triggerAsyncId is omitted then
257 * async_hook.executionAsyncId() is used.
258 * @param type The type of async event.
259 * @param triggerAsyncId The ID of the execution context that created
260 * this async event (default: `executionAsyncId()`), or an
261 * AsyncResourceOptions object (since 9.3)
262 */
263 constructor(type: string, triggerAsyncId?: number | AsyncResourceOptions);
264 /**
265 * Binds the given function to the current execution context.
266 *
267 * The returned function will have an `asyncResource` property referencing
268 * the `AsyncResource` to which the function is bound.
269 * @since v14.8.0, v12.19.0
270 * @param fn The function to bind to the current execution context.
271 * @param type An optional name to associate with the underlying `AsyncResource`.
272 */
273 static bind<Func extends (this: ThisArg, ...args: any[]) => any, ThisArg>(
274 fn: Func,
275 type?: string,
276 thisArg?: ThisArg
277 ): Func & {
278 asyncResource: AsyncResource;
279 };
280 /**
281 * Binds the given function to execute to this `AsyncResource`'s scope.
282 *
283 * The returned function will have an `asyncResource` property referencing
284 * the `AsyncResource` to which the function is bound.
285 * @since v14.8.0, v12.19.0
286 * @param fn The function to bind to the current `AsyncResource`.
287 */
288 bind<Func extends (...args: any[]) => any>(
289 fn: Func
290 ): Func & {
291 asyncResource: AsyncResource;
292 };
293 /**
294 * Call the provided function with the provided arguments in the execution context
295 * of the async resource. This will establish the context, trigger the AsyncHooks
296 * before callbacks, call the function, trigger the AsyncHooks after callbacks, and
297 * then restore the original execution context.
298 * @since v9.6.0
299 * @param fn The function to call in the execution context of this async resource.
300 * @param thisArg The receiver to be used for the function call.
301 * @param args Optional arguments to pass to the function.
302 */
303 runInAsyncScope<This, Result>(fn: (this: This, ...args: any[]) => Result, thisArg?: This, ...args: any[]): Result;
304 /**
305 * Call all `destroy` hooks. This should only ever be called once. An error will
306 * be thrown if it is called more than once. This **must** be manually called. If
307 * the resource is left to be collected by the GC then the `destroy` hooks will
308 * never be called.
309 * @return A reference to `asyncResource`.
310 */
311 emitDestroy(): this;
312 /**
313 * @return The unique `asyncId` assigned to the resource.
314 */
315 asyncId(): number;
316 /**
317 *
318 * @return The same `triggerAsyncId` that is passed to the `AsyncResource` constructor.
319 */
320 triggerAsyncId(): number;
321 }
322 /**
323 * This class creates stores that stay coherent through asynchronous operations.
324 *
325 * 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
326 * implementation that involves significant optimizations that are non-obvious to
327 * implement.
328 *
329 * The following example uses `AsyncLocalStorage` to build a simple logger
330 * that assigns IDs to incoming HTTP requests and includes them in messages
331 * logged within each request.
332 *
333 * ```js
334 * const http = require('http');
335 * const { AsyncLocalStorage } = require('async_hooks');
336 *
337 * const asyncLocalStorage = new AsyncLocalStorage();
338 *
339 * function logWithId(msg) {
340 * const id = asyncLocalStorage.getStore();
341 * console.log(`${id !== undefined ? id : '-'}:`, msg);
342 * }
343 *
344 * let idSeq = 0;
345 * http.createServer((req, res) => {
346 * asyncLocalStorage.run(idSeq++, () => {
347 * logWithId('start');
348 * // Imagine any chain of async operations here
349 * setImmediate(() => {
350 * logWithId('finish');
351 * res.end();
352 * });
353 * });
354 * }).listen(8080);
355 *
356 * http.get('http://localhost:8080');
357 * http.get('http://localhost:8080');
358 * // Prints:
359 * // 0: start
360 * // 1: start
361 * // 0: finish
362 * // 1: finish
363 * ```
364 *
365 * Each instance of `AsyncLocalStorage` maintains an independent storage context.
366 * Multiple instances can safely exist simultaneously without risk of interfering
367 * with each other data.
368 * @since v13.10.0, v12.17.0
369 */
370 class AsyncLocalStorage<T> {
371 /**
372 * Disables the instance of `AsyncLocalStorage`. All subsequent calls
373 * to `asyncLocalStorage.getStore()` will return `undefined` until`asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()` is called again.
374 *
375 * When calling `asyncLocalStorage.disable()`, all current contexts linked to the
376 * instance will be exited.
377 *
378 * Calling `asyncLocalStorage.disable()` is required before the`asyncLocalStorage` can be garbage collected. This does not apply to stores
379 * provided by the `asyncLocalStorage`, as those objects are garbage collected
380 * along with the corresponding async resources.
381 *
382 * Use this method when the `asyncLocalStorage` is not in use anymore
383 * in the current process.
384 * @since v13.10.0, v12.17.0
385 * @experimental
386 */
387 disable(): void;
388 /**
389 * Returns the current store.
390 * If called outside of an asynchronous context initialized by
391 * calling `asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()`, it
392 * returns `undefined`.
393 * @since v13.10.0, v12.17.0
394 */
395 getStore(): T | undefined;
396 /**
397 * Runs a function synchronously within a context and returns its
398 * return value. The store is not accessible outside of the callback function or
399 * the asynchronous operations created within the callback.
400 *
401 * The optional `args` are passed to the callback function.
402 *
403 * If the callback function throws an error, the error is thrown by `run()` too.
404 * The stacktrace is not impacted by this call and the context is exited.
405 *
406 * Example:
407 *
408 * ```js
409 * const store = { id: 2 };
410 * try {
411 * asyncLocalStorage.run(store, () => {
412 * asyncLocalStorage.getStore(); // Returns the store object
413 * throw new Error();
414 * });
415 * } catch (e) {
416 * asyncLocalStorage.getStore(); // Returns undefined
417 * // The error will be caught here
418 * }
419 * ```
420 * @since v13.10.0, v12.17.0
421 */
422 run<R, TArgs extends any[]>(store: T, callback: (...args: TArgs) => R, ...args: TArgs): R;
423 /**
424 * Runs a function synchronously outside of a context and returns its
425 * return value. The store is not accessible within the callback function or
426 * the asynchronous operations created within the callback. Any `getStore()`call done within the callback function will always return `undefined`.
427 *
428 * The optional `args` are passed to the callback function.
429 *
430 * If the callback function throws an error, the error is thrown by `exit()` too.
431 * The stacktrace is not impacted by this call and the context is re-entered.
432 *
433 * Example:
434 *
435 * ```js
436 * // Within a call to run
437 * try {
438 * asyncLocalStorage.getStore(); // Returns the store object or value
439 * asyncLocalStorage.exit(() => {
440 * asyncLocalStorage.getStore(); // Returns undefined
441 * throw new Error();
442 * });
443 * } catch (e) {
444 * asyncLocalStorage.getStore(); // Returns the same object or value
445 * // The error will be caught here
446 * }
447 * ```
448 * @since v13.10.0, v12.17.0
449 * @experimental
450 */
451 exit<R, TArgs extends any[]>(callback: (...args: TArgs) => R, ...args: TArgs): R;
452 /**
453 * Transitions into the context for the remainder of the current
454 * synchronous execution and then persists the store through any following
455 * asynchronous calls.
456 *
457 * Example:
458 *
459 * ```js
460 * const store = { id: 1 };
461 * // Replaces previous store with the given store object
462 * asyncLocalStorage.enterWith(store);
463 * asyncLocalStorage.getStore(); // Returns the store object
464 * someAsyncOperation(() => {
465 * asyncLocalStorage.getStore(); // Returns the same object
466 * });
467 * ```
468 *
469 * This transition will continue for the _entire_ synchronous execution.
470 * This means that if, for example, the context is entered within an event
471 * handler subsequent event handlers will also run within that context unless
472 * specifically bound to another context with an `AsyncResource`. That is why`run()` should be preferred over `enterWith()` unless there are strong reasons
473 * to use the latter method.
474 *
475 * ```js
476 * const store = { id: 1 };
477 *
478 * emitter.on('my-event', () => {
479 * asyncLocalStorage.enterWith(store);
480 * });
481 * emitter.on('my-event', () => {
482 * asyncLocalStorage.getStore(); // Returns the same object
483 * });
484 *
485 * asyncLocalStorage.getStore(); // Returns undefined
486 * emitter.emit('my-event');
487 * asyncLocalStorage.getStore(); // Returns the same object
488 * ```
489 * @since v13.11.0, v12.17.0
490 * @experimental
491 */
492 enterWith(store: T): void;
493 }
494}
495declare module 'node:async_hooks' {
496 export * from 'async_hooks';
497}
498
\No newline at end of file