{"action":"created","comment":{"url":"https://api.github.com/repos/nodejs/node-eps/pulls/comments/69718563","id":69718563,"diff_hunk":"@@ -0,0 +1,419 @@\n+| Title  | AsyncWrap API |\n+|--------|---------------|\n+| Author | @trevnorris   |\n+| Status | DRAFT         |\n+| Date   | 2016-04-05    |\n+\n+## Description\n+\n+Since its initial introduction along side the `AsyncListener` API, `AsyncWrap`\n+has slowly evolved to ensure a generalized API that would serve as a solid base\n+for module authors who wished to add listeners to the event loop's life cycle.\n+Some of the use cases `AsyncWrap` has covered are long stack traces,\n+continuation local storage, profiling of asynchronous requests and resource\n+tracking.\n+\n+It must be clarified that the `AsyncWrap` API is not meant to abstract away\n+Node's implementation details, and is in fact intentional. Observing how\n+operations are performed, not simply how they appear to perform from the public\n+API, is a key point in its usability. For a real world example, a user was\n+having difficulty figuring out why their `http.get()` calls were taking so\n+long. Because `AsyncHooks` exposed the `dns.lookup()` request to resolve the\n+host being made by the `net` module it was trivial to write a performance\n+measurement that exposed the hidden culprit. Which was that DNS resolution was\n+taking much longer than expected.\n+\n+A small amount of abstraction is necessary to accommodate the conceptual nature\n+of the API. For example, the `HTTPParser` is not destructed but instead placed\n+into an unused pool to be used later. Even so, at the time it is placed into\n+the pool  the `destroy()` callback will run and then the id assigned to that\n+instance will be removed. If that resource is again requested then it will be\n+assigned a new id and will run `init()` again.\n+\n+\n+## Goals\n+\n+The intent for the initial release is to provide the most minimal set of API\n+hooks that don't inhibit module authors from writing tools addressing anything\n+in this problem space. In order to remain minimal, all potential features for\n+initial release will first be judged on whether they can be achieved by the\n+existing public API. If so then such a feature won't be included.\n+\n+If the feature cannot be done with the existing public API then discussion will\n+be had on whether requested functionality should be included in the initial\n+API. If so then the best course of action to include the capabilities of the\n+request will be discussed and performed. Meaning, the resulting API may not be\n+the same as initially requested, but the user will be able to achieve the same\n+end result.\n+\n+Performance impact of `AsyncWrap` should be zero if not being used, and near\n+zero while being used. The performance overhead of `AsyncHook` callbacks\n+supplied by the user should account for essentially all the performance\n+overhead.\n+\n+\n+## Terminology\n+\n+Because of the potential ambiguity for those not familiar with the terms \"handle\"\n+and \"request\" they should be well defined.\n+\n+Handles are a reference to a system resource. The resource handle can be a\n+simple identifier, such as a file descriptor, or it can be a pointer that\n+allows access to further information, such as `uv_tcp_t`. Realize that the\n+latter still relies on a file descriptor, but has been encapsulated in a data\n+structure containing additional information that allows the application to\n+work with it.\n+\n+Requests are short lived data structures created to accomplish one task. The\n+callback for a request should always and only ever fire one time. When the\n+assigned task has either completed or encountered an error. Requests are used\n+by handles to perform work. Such as accepting a new connection or writing data\n+to disk.\n+\n+\n+## API\n+\n+### Overview\n+\n+```js\n+// Standard way of requiring a module. Snake case follows core module\n+// convention.\n+const async_wrap = require('async_wrap');\n+\n+// List of asynchronous subsystems (e.g. CRYPTO or TCPWRAP). Can be used for\n+// trace filtering of events.\n+const subsystems = async_wrap.subsystems;\n+\n+// Retrieve a handle by its id. The id will have been passed to the init()\n+// callback. Reason for this API is to prevent users from holding references\n+// to the handles themselves. Thus possibly preventing GC from cleaning up\n+// the handle and ever firing the destroy() callback.\n+const handle = async_wrap.getHandleById(n);\n+\n+// init() is called during object construction. The handle will have not\n+// completed construction when this callback runs. So not all fields will have\n+// populated.\n+function init(id, type, parentId) { }\n+\n+// pre() is called just before the handle's callback is called. It can be\n+// called 0-N times for handles (e.g. TCPWRAP), and should be called exactly 1\n+// time for requests (e.g. FSREQWRAP).\n+function pre(id) { }\n+\n+// post() is called just after the handle's callback has finished, and will be\n+// called regardless whether the handle's callback threw. If the handle's\n+// callback did throw then hasThrown will be true.\n+function post(id, hasThrown) { }\n+\n+// destroy() is called when an AsyncWrap instance is destroyed. In cases like\n+// HTTPPARSER where the resource is reused, or timers where the handle is only\n+// a JS object, destroy() will be triggered manually soon after post() has\n+// completed.\n+function destroy(id) { }\n+\n+// Create a new instance and add each callback to the corresponding hook.\n+var asyncHook = new AsyncHook({ init, pre, post, destroy });\n+\n+// Enable hooks for the current synchronous execution scope. This will ensure\n+// the hooks are not in effect in case of multiple returns, or if an exception\n+// is thrown.\n+asyncHook.scope();\n+\n+// Allow callbacks of this AsyncHook instance to fire. This is not an implicit\n+// action after running the constructor, and must be explicitly run to begin\n+// executing callbacks.\n+asyncHook.enable();\n+\n+// Disable listening for new asynchronous events. Though this will not prevent\n+// callbacks from firing on asynchronous chains that have already run within\n+// the scope of an enabled AsyncHook instance.\n+asyncHook.disable();\n+\n+// Unlike disable(), prevent any hook callback from firing again in the future.\n+// Future hooks can be added by running scope()/enable() again.\n+// TODO: I am not sure all of this is possible. Some investigation is necessary.\n+asyncHook.remove();\n+```\n+\n+\n+### `async_wrap`\n+\n+The object returned from `require('async_wrap')`.\n+\n+\n+#### `async_wrap.subsystems`\n+\n+List of all subsystems that may trigger the `init` callback. These subsystems\n+group relevant calls together. For example the `CRYPTO` provider encompasses\n+all calls from the crypto library that only creates a request. Purposes of this\n+is to allow quick filtering or reporting of incoming requests.\n+\n+**Note(trevnorris):** \"provider\" was originally intended to be \"subsystem\" then\n+later essentially turned into the class name, unless the class being\n+instantiated inherited directly from `AsyncWrap`. so should subsystems simply be\n+changed to include the name of every class constructor? or should it properly\n+group calls together, such as `TCPWRAP` and `TCPCONNECTWRAP` into a single TCP\n+provider? or possibly both.\n+\n+\n+#### `async_wrap.getHandleById(id)`\n+\n+Some handles are cleaned up by the garbage collector. Preventing the user from\n+being able to store those handles for future reference. Instead node keeps\n+internal references to each handle that aren't affected by GC. They can then be","path":"XXX-asyncwrap-api.md","position":163,"original_position":163,"commit_id":"9e95a3fd16f053e1fc0d59226a26bb7fbc552d30","original_commit_id":"9e95a3fd16f053e1fc0d59226a26bb7fbc552d30","user":{"login":"rvagg","id":495647,"avatar_url":"https://avatars.githubusercontent.com/u/495647?v=3","gravatar_id":"","url":"https://api.github.com/users/rvagg","html_url":"https://github.com/rvagg","followers_url":"https://api.github.com/users/rvagg/followers","following_url":"https://api.github.com/users/rvagg/following{/other_user}","gists_url":"https://api.github.com/users/rvagg/gists{/gist_id}","starred_url":"https://api.github.com/users/rvagg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rvagg/subscriptions","organizations_url":"https://api.github.com/users/rvagg/orgs","repos_url":"https://api.github.com/users/rvagg/repos","events_url":"https://api.github.com/users/rvagg/events{/privacy}","received_events_url":"https://api.github.com/users/rvagg/received_events","type":"User","site_admin":false},"body":"s/aren't/isn't","created_at":"2016-07-06T12:11:37Z","updated_at":"2016-07-06T12:11:37Z","html_url":"https://github.com/nodejs/node-eps/pull/18#discussion_r69718563","pull_request_url":"https://api.github.com/repos/nodejs/node-eps/pulls/18","_links":{"self":{"href":"https://api.github.com/repos/nodejs/node-eps/pulls/comments/69718563"},"html":{"href":"https://github.com/nodejs/node-eps/pull/18#discussion_r69718563"},"pull_request":{"href":"https://api.github.com/repos/nodejs/node-eps/pulls/18"}}},"pull_request":{"url":"https://api.github.com/repos/nodejs/node-eps/pulls/18","id":68137447,"html_url":"https://github.com/nodejs/node-eps/pull/18","diff_url":"https://github.com/nodejs/node-eps/pull/18.diff","patch_url":"https://github.com/nodejs/node-eps/pull/18.patch","issue_url":"https://api.github.com/repos/nodejs/node-eps/issues/18","number":18,"state":"open","locked":false,"title":"AsyncWrap public API proposal","user":{"login":"trevnorris","id":289174,"avatar_url":"https://avatars.githubusercontent.com/u/289174?v=3","gravatar_id":"","url":"https://api.github.com/users/trevnorris","html_url":"https://github.com/trevnorris","followers_url":"https://api.github.com/users/trevnorris/followers","following_url":"https://api.github.com/users/trevnorris/following{/other_user}","gists_url":"https://api.github.com/users/trevnorris/gists{/gist_id}","starred_url":"https://api.github.com/users/trevnorris/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trevnorris/subscriptions","organizations_url":"https://api.github.com/users/trevnorris/orgs","repos_url":"https://api.github.com/users/trevnorris/repos","events_url":"https://api.github.com/users/trevnorris/events{/privacy}","received_events_url":"https://api.github.com/users/trevnorris/received_events","type":"User","site_admin":false},"body":"After much investigation and communication this is the API that has\r\nsurfaced. Meant to be minimal, not impose any performance penalty to\r\ncore when not being used, and minimal impact when it is used, this\r\nshould serve public needs that have been expressed over the last two\r\nyears.\r\n\r\n@nodejs/ctc I'd like the initial review explicitly from the CTC before this is opened for too much external debate. Because experience has shown me that there will be suggestions/changes for those who want specific features and/or additions to suit their specific use case. Usually not taking the time to realize that this API is enough. They just need to write the additional code for the hooks.","created_at":"2016-04-27T22:43:35Z","updated_at":"2016-07-06T12:11:37Z","closed_at":null,"merged_at":null,"merge_commit_sha":"29eb83e2abf6e9081889aab89885991f8dab1f72","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/nodejs/node-eps/pulls/18/commits","review_comments_url":"https://api.github.com/repos/nodejs/node-eps/pulls/18/comments","review_comment_url":"https://api.github.com/repos/nodejs/node-eps/pulls/comments{/number}","comments_url":"https://api.github.com/repos/nodejs/node-eps/issues/18/comments","statuses_url":"https://api.github.com/repos/nodejs/node-eps/statuses/9e95a3fd16f053e1fc0d59226a26bb7fbc552d30","head":{"label":"nodejs:async-wrap-ep","ref":"async-wrap-ep","sha":"9e95a3fd16f053e1fc0d59226a26bb7fbc552d30","user":{"login":"nodejs","id":9950313,"avatar_url":"https://avatars.githubusercontent.com/u/9950313?v=3","gravatar_id":"","url":"https://api.github.com/users/nodejs","html_url":"https://github.com/nodejs","followers_url":"https://api.github.com/users/nodejs/followers","following_url":"https://api.github.com/users/nodejs/following{/other_user}","gists_url":"https://api.github.com/users/nodejs/gists{/gist_id}","starred_url":"https://api.github.com/users/nodejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nodejs/subscriptions","organizations_url":"https://api.github.com/users/nodejs/orgs","repos_url":"https://api.github.com/users/nodejs/repos","events_url":"https://api.github.com/users/nodejs/events{/privacy}","received_events_url":"https://api.github.com/users/nodejs/received_events","type":"Organization","site_admin":false},"repo":{"id":48204104,"name":"node-eps","full_name":"nodejs/node-eps","owner":{"login":"nodejs","id":9950313,"avatar_url":"https://avatars.githubusercontent.com/u/9950313?v=3","gravatar_id":"","url":"https://api.github.com/users/nodejs","html_url":"https://github.com/nodejs","followers_url":"https://api.github.com/users/nodejs/followers","following_url":"https://api.github.com/users/nodejs/following{/other_user}","gists_url":"https://api.github.com/users/nodejs/gists{/gist_id}","starred_url":"https://api.github.com/users/nodejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nodejs/subscriptions","organizations_url":"https://api.github.com/users/nodejs/orgs","repos_url":"https://api.github.com/users/nodejs/repos","events_url":"https://api.github.com/users/nodejs/events{/privacy}","received_events_url":"https://api.github.com/users/nodejs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nodejs/node-eps","description":"Node.js Enhancement Proposals for discussion on future API additions/changes to Node core","fork":false,"url":"https://api.github.com/repos/nodejs/node-eps","forks_url":"https://api.github.com/repos/nodejs/node-eps/forks","keys_url":"https://api.github.com/repos/nodejs/node-eps/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nodejs/node-eps/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nodejs/node-eps/teams","hooks_url":"https://api.github.com/repos/nodejs/node-eps/hooks","issue_events_url":"https://api.github.com/repos/nodejs/node-eps/issues/events{/number}","events_url":"https://api.github.com/repos/nodejs/node-eps/events","assignees_url":"https://api.github.com/repos/nodejs/node-eps/assignees{/user}","branches_url":"https://api.github.com/repos/nodejs/node-eps/branches{/branch}","tags_url":"https://api.github.com/repos/nodejs/node-eps/tags","blobs_url":"https://api.github.com/repos/nodejs/node-eps/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nodejs/node-eps/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nodejs/node-eps/git/refs{/sha}","trees_url":"https://api.github.com/repos/nodejs/node-eps/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nodejs/node-eps/statuses/{sha}","languages_url":"https://api.github.com/repos/nodejs/node-eps/languages","stargazers_url":"https://api.github.com/repos/nodejs/node-eps/stargazers","contributors_url":"https://api.github.com/repos/nodejs/node-eps/contributors","subscribers_url":"https://api.github.com/repos/nodejs/node-eps/subscribers","subscription_url":"https://api.github.com/repos/nodejs/node-eps/subscription","commits_url":"https://api.github.com/repos/nodejs/node-eps/commits{/sha}","git_commits_url":"https://api.github.com/repos/nodejs/node-eps/git/commits{/sha}","comments_url":"https://api.github.com/repos/nodejs/node-eps/comments{/number}","issue_comment_url":"https://api.github.com/repos/nodejs/node-eps/issues/comments{/number}","contents_url":"https://api.github.com/repos/nodejs/node-eps/contents/{+path}","compare_url":"https://api.github.com/repos/nodejs/node-eps/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nodejs/node-eps/merges","archive_url":"https://api.github.com/repos/nodejs/node-eps/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nodejs/node-eps/downloads","issues_url":"https://api.github.com/repos/nodejs/node-eps/issues{/number}","pulls_url":"https://api.github.com/repos/nodejs/node-eps/pulls{/number}","milestones_url":"https://api.github.com/repos/nodejs/node-eps/milestones{/number}","notifications_url":"https://api.github.com/repos/nodejs/node-eps/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nodejs/node-eps/labels{/name}","releases_url":"https://api.github.com/repos/nodejs/node-eps/releases{/id}","deployments_url":"https://api.github.com/repos/nodejs/node-eps/deployments","created_at":"2015-12-17T23:39:07Z","updated_at":"2016-07-04T18:05:45Z","pushed_at":"2016-07-04T16:05:57Z","git_url":"git://github.com/nodejs/node-eps.git","ssh_url":"git@github.com:nodejs/node-eps.git","clone_url":"https://github.com/nodejs/node-eps.git","svn_url":"https://github.com/nodejs/node-eps","homepage":null,"size":93,"stargazers_count":133,"watchers_count":133,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":22,"mirror_url":null,"open_issues_count":16,"forks":22,"open_issues":16,"watchers":133,"default_branch":"master"}},"base":{"label":"nodejs:master","ref":"master","sha":"5dae5a537c2d56fbaf23aaf2ae9da15e74474021","user":{"login":"nodejs","id":9950313,"avatar_url":"https://avatars.githubusercontent.com/u/9950313?v=3","gravatar_id":"","url":"https://api.github.com/users/nodejs","html_url":"https://github.com/nodejs","followers_url":"https://api.github.com/users/nodejs/followers","following_url":"https://api.github.com/users/nodejs/following{/other_user}","gists_url":"https://api.github.com/users/nodejs/gists{/gist_id}","starred_url":"https://api.github.com/users/nodejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nodejs/subscriptions","organizations_url":"https://api.github.com/users/nodejs/orgs","repos_url":"https://api.github.com/users/nodejs/repos","events_url":"https://api.github.com/users/nodejs/events{/privacy}","received_events_url":"https://api.github.com/users/nodejs/received_events","type":"Organization","site_admin":false},"repo":{"id":48204104,"name":"node-eps","full_name":"nodejs/node-eps","owner":{"login":"nodejs","id":9950313,"avatar_url":"https://avatars.githubusercontent.com/u/9950313?v=3","gravatar_id":"","url":"https://api.github.com/users/nodejs","html_url":"https://github.com/nodejs","followers_url":"https://api.github.com/users/nodejs/followers","following_url":"https://api.github.com/users/nodejs/following{/other_user}","gists_url":"https://api.github.com/users/nodejs/gists{/gist_id}","starred_url":"https://api.github.com/users/nodejs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nodejs/subscriptions","organizations_url":"https://api.github.com/users/nodejs/orgs","repos_url":"https://api.github.com/users/nodejs/repos","events_url":"https://api.github.com/users/nodejs/events{/privacy}","received_events_url":"https://api.github.com/users/nodejs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nodejs/node-eps","description":"Node.js Enhancement Proposals for discussion on future API additions/changes to Node core","fork":false,"url":"https://api.github.com/repos/nodejs/node-eps","forks_url":"https://api.github.com/repos/nodejs/node-eps/forks","keys_url":"https://api.github.com/repos/nodejs/node-eps/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nodejs/node-eps/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nodejs/node-eps/teams","hooks_url":"https://api.github.com/repos/nodejs/node-eps/hooks","issue_events_url":"https://api.github.com/repos/nodejs/node-eps/issues/events{/number}","events_url":"https://api.github.com/repos/nodejs/node-eps/events","assignees_url":"https://api.github.com/repos/nodejs/node-eps/assignees{/user}","branches_url":"https://api.github.com/repos/nodejs/node-eps/branches{/branch}","tags_url":"https://api.github.com/repos/nodejs/node-eps/tags","blobs_url":"https://api.github.com/repos/nodejs/node-eps/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nodejs/node-eps/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nodejs/node-eps/git/refs{/sha}","trees_url":"https://api.github.com/repos/nodejs/node-eps/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nodejs/node-eps/statuses/{sha}","languages_url":"https://api.github.com/repos/nodejs/node-eps/languages","stargazers_url":"https://api.github.com/repos/nodejs/node-eps/stargazers","contributors_url":"https://api.github.com/repos/nodejs/node-eps/contributors","subscribers_url":"https://api.github.com/repos/nodejs/node-eps/subscribers","subscription_url":"https://api.github.com/repos/nodejs/node-eps/subscription","commits_url":"https://api.github.com/repos/nodejs/node-eps/commits{/sha}","git_commits_url":"https://api.github.com/repos/nodejs/node-eps/git/commits{/sha}","comments_url":"https://api.github.com/repos/nodejs/node-eps/comments{/number}","issue_comment_url":"https://api.github.com/repos/nodejs/node-eps/issues/comments{/number}","contents_url":"https://api.github.com/repos/nodejs/node-eps/contents/{+path}","compare_url":"https://api.github.com/repos/nodejs/node-eps/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nodejs/node-eps/merges","archive_url":"https://api.github.com/repos/nodejs/node-eps/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nodejs/node-eps/downloads","issues_url":"https://api.github.com/repos/nodejs/node-eps/issues{/number}","pulls_url":"https://api.github.com/repos/nodejs/node-eps/pulls{/number}","milestones_url":"https://api.github.com/repos/nodejs/node-eps/milestones{/number}","notifications_url":"https://api.github.com/repos/nodejs/node-eps/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nodejs/node-eps/labels{/name}","releases_url":"https://api.github.com/repos/nodejs/node-eps/releases{/id}","deployments_url":"https://api.github.com/repos/nodejs/node-eps/deployments","created_at":"2015-12-17T23:39:07Z","updated_at":"2016-07-04T18:05:45Z","pushed_at":"2016-07-04T16:05:57Z","git_url":"git://github.com/nodejs/node-eps.git","ssh_url":"git@github.com:nodejs/node-eps.git","clone_url":"https://github.com/nodejs/node-eps.git","svn_url":"https://github.com/nodejs/node-eps","homepage":null,"size":93,"stargazers_count":133,"watchers_count":133,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":22,"mirror_url":null,"open_issues_count":16,"forks":22,"open_issues":16,"watchers":133,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/nodejs/node-eps/pulls/18"},"html":{"href":"https://github.com/nodejs/node-eps/pull/18"},"issue":{"href":"https://api.github.com/repos/nodejs/node-eps/issues/18"},"comments":{"href":"https://api.github.com/repos/nodejs/node-eps/issues/18/comments"},"review_comments":{"href":"https://api.github.com/repos/nodejs/node-eps/pulls/18/comments"},"review_comment":{"href":"https://api.github.com/repos/nodejs/node-eps/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/nodejs/node-eps/pulls/18/commits"},"statuses":{"href":"https://api.github.com/repos/nodejs/node-eps/statuses/9e95a3fd16f053e1fc0d59226a26bb7fbc552d30"}}}}
{"actor":{"display_login":"rvagg"}}