{"action":"created","comment":{"url":"https://api.github.com/repos/restify/node-restify/pulls/comments/166127250","pull_request_review_id":94158326,"id":166127250,"diff_hunk":"@@ -807,32 +809,47 @@ function patch(Request) {\n             time: self._timerMap[name]\n         });\n \n-        dtrace._rstfy_probes['handler-done'].fire(function fire() {\n-            return [\n-                self.serverName,\n-                self._currentRoute, // set in server._run\n-                name,\n-                self._dtraceId\n-            ];\n-        });\n+        if (self.dtrace) {\n+            dtrace._rstfy_probes['handler-done'].fire(function fire() {\n+                return [\n+                    self.serverName,\n+                    self._currentRoute, // set in server._run\n+                    name,\n+                    self._dtraceId\n+                ];\n+            });\n+        }\n     };\n \n     /**\n      * Returns the connection state of the request. Current possible values are:\n      * - `close` - when the request has been closed by the clien\n-     * - `aborted` - when the socket was closed unexpectedly\n      *\n      * @public\n      * @memberof Request\n      * @instance\n      * @function connectionState\n-     * @returns {String} connection state (`\"closed\"`, `\"aborted\"`)\n+     * @returns {String} connection state (`\"close\"`)\n      */\n     Request.prototype.connectionState = function connectionState() {\n         var self = this;\n         return self._connectionState;\n     };\n \n+    /**\n+     * Returns true when connection state is \"close\"\n+     *\n+     * @private\n+     * @memberof Request\n+     * @instance\n+     * @function closed\n+     * @returns {Boolean} is closed\n+     */\n+    Request.prototype.closed = function closed() {","path":"lib/request.js","position":75,"original_position":75,"commit_id":"5e096d0cbf0d1bd8a651165c66649e9450c1f4e0","original_commit_id":"5e096d0cbf0d1bd8a651165c66649e9450c1f4e0","user":{"login":"DonutEspresso","id":2381315,"avatar_url":"https://avatars3.githubusercontent.com/u/2381315?v=4","gravatar_id":"","url":"https://api.github.com/users/DonutEspresso","html_url":"https://github.com/DonutEspresso","followers_url":"https://api.github.com/users/DonutEspresso/followers","following_url":"https://api.github.com/users/DonutEspresso/following{/other_user}","gists_url":"https://api.github.com/users/DonutEspresso/gists{/gist_id}","starred_url":"https://api.github.com/users/DonutEspresso/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DonutEspresso/subscriptions","organizations_url":"https://api.github.com/users/DonutEspresso/orgs","repos_url":"https://api.github.com/users/DonutEspresso/repos","events_url":"https://api.github.com/users/DonutEspresso/events{/privacy}","received_events_url":"https://api.github.com/users/DonutEspresso/received_events","type":"User","site_admin":false},"body":"👍 ","created_at":"2018-02-05T22:06:36Z","updated_at":"2018-02-05T22:58:14Z","html_url":"https://github.com/restify/node-restify/pull/1561#discussion_r166127250","pull_request_url":"https://api.github.com/repos/restify/node-restify/pulls/1561","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/restify/node-restify/pulls/comments/166127250"},"html":{"href":"https://github.com/restify/node-restify/pull/1561#discussion_r166127250"},"pull_request":{"href":"https://api.github.com/repos/restify/node-restify/pulls/1561"}}},"pull_request":{"url":"https://api.github.com/repos/restify/node-restify/pulls/1561","id":151639084,"html_url":"https://github.com/restify/node-restify/pull/1561","diff_url":"https://github.com/restify/node-restify/pull/1561.diff","patch_url":"https://github.com/restify/node-restify/pull/1561.patch","issue_url":"https://api.github.com/repos/restify/node-restify/issues/1561","number":1561,"state":"open","locked":false,"title":"7.x: new router and middleware system","user":{"login":"hekike","id":1764512,"avatar_url":"https://avatars0.githubusercontent.com/u/1764512?v=4","gravatar_id":"","url":"https://api.github.com/users/hekike","html_url":"https://github.com/hekike","followers_url":"https://api.github.com/users/hekike/followers","following_url":"https://api.github.com/users/hekike/following{/other_user}","gists_url":"https://api.github.com/users/hekike/gists{/gist_id}","starred_url":"https://api.github.com/users/hekike/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hekike/subscriptions","organizations_url":"https://api.github.com/users/hekike/orgs","repos_url":"https://api.github.com/users/hekike/repos","events_url":"https://api.github.com/users/hekike/events{/privacy}","received_events_url":"https://api.github.com/users/hekike/received_events","type":"User","site_admin":false},"body":"Replace the router and middleware logic with a more performant solution.\r\nGoal: zero or almost zero API/functionality change with significant performance improvement.\r\n\r\nPt 1. (https://github.com/restify/node-restify/pull/1554) was nice for dumb servers and synthetic tests; this should be more useful for real-world applications, especially ones with many routes.\r\n\r\n# Changes\r\n\r\n- Replaces the router with the Radix Tree based [find-my-way](https://github.com/delvedor/find-my-way)\r\n- New middleware system called `chain.js`, similar to [connect](https://github.com/senchalabs/connect)\r\n- Move versioning and contentType routing into a `conditionalHandler` plugin, see:\r\n\r\n```js\r\nserver.use(restify.plugins.conditionalHandler({\r\n   contentType: 'application/json',\r\n   version: '1.0.0'\r\n   handler: function (req, res, next) {\r\n       next();\r\n   })\r\n});\r\n\r\nserver.get('/hello/:name', restify.plugins.conditionalHandler([\r\n  {\r\n     version: '1.0.0',\r\n     handler: function(req, res, next) { res.send('1.x') }\r\n  },\r\n  {\r\n     version: ['1.5.0', '2.0.0'],\r\n     handler: function(req, res, next) { res.send('1.5.x, 2.x') }\r\n  },\r\n  {\r\n     version: '3.0.0',\r\n     contentType: ['text/html', 'text/html']\r\n     handler: function(req, res, next) { res.send('3.x, text') }\r\n  },\r\n  {\r\n     version: '3.0.0',\r\n     contentType: 'application/json'\r\n     handler: function(req, res, next) { res.send('3.x, json') }\r\n  }\r\n]);\r\n```\r\n\r\nHints for review:\r\n\r\n- `response.js`: 100% new, do not review it by diff\r\n- `server.js`: the complete request handling logic is new, I recommend to review it as a new file\r\n\r\n# TODO\r\n\r\n- [x] replacing router\r\n- [x] replacing middleware system\r\n- [x] content-type based routing *(moved to `conditioalHandler` plugin)*\r\n- [x] router versioning, see: https://github.com/delvedor/find-my-way/issues/39 *(moved to `conditioalHandler` plugin)*\r\n- [x] fix plugin tests *(114 passing,  39 failing)*\r\n- [x] ~~revisit fix response tests port *(why did it fail with absolut url?)*~~\r\n- [x] add back DTrace support to server.js\r\n- [x] `router` tests\r\n- [x] `chain` tests\r\n- [x] re-visit `once` for handler `next`\r\n- [x] router unmount, see: https://github.com/delvedor/find-my-way/issues/40 *(tests are disabled temporary)*\r\n- [x] Write migration guide\r\n\r\n# Breaking Changes\r\n\r\n- Nonstrict-routing is not available\r\n- Limited `RegExp` usage in router path see https://github.com/delvedor/find-my-way\r\n- Remove already deprecated `next.ifError`\r\n- disable DTrace probes by default *( I know it's painful, but most of the people don't know/use it, it causes ~10% throughput improvement in all benchmark tests)*, `createServer({ dtrace: true })`\r\n- Router versioning and contentType routing moved to `conditioalHandler` plugin, see above\r\n- `once ` is not applied automatically for multiple `next()` calls, use the new `onceNext: true` server option, `strictNext` is the same\r\n\r\n# Results\r\n\r\nTest machine: Mid 2014 MBP, 2.6 i5 16GB RAM \r\n(~30% improvement compared to `6.3.2` (https://github.com/restify/node-restify/pull/1554), ~50% compared to `6.3.1`)\r\n\r\n## Result: dumb server\r\n\r\n*Note: Most of the performance improvements in these benchmarks come from the new middleware logic and other optimizations, the router performance is not tested here as it uses LRU cache.*\r\n\r\n```\r\n---- response-json ----\r\n✔ Results saved for head/response-json\r\n✔ Results saved for stable/response-json\r\nresponse-json throughput:\r\n{\r\n    \"significant\": \"***\",\r\n    \"equal\": false,\r\n    \"wins\": \"head\",\r\n    \"diff\": \"30.21%\"\r\n}\r\n\r\n---- response-text ----\r\n✔ Results saved for head/response-text\r\n✔ Results saved for stable/response-text\r\nresponse-text throughput:\r\n{\r\n    \"significant\": \"***\",\r\n    \"equal\": false,\r\n    \"wins\": \"head\",\r\n    \"diff\": \"34.18%\"\r\n}\r\n```\r\n\r\n## Result: middleware\r\n\r\n```\r\n---- middleware ----\r\n✔ Results saved for head/middleware\r\n✔ Results saved for stable/middleware\r\nmiddleware throughput:\r\n{\r\n    \"significant\": \"***\",\r\n    \"equal\": false,\r\n    \"wins\": \"head\",\r\n    \"diff\": \"44.68%\"\r\n}\r\n```\r\n\r\n## Result: heavy router\r\n\r\n*Note: Disabling (mocking out) cache in a stable version: it's not fair as it aims to the worst case, cache hit ratio is 0%. However, it's still better than the worst case scenario as it least doesn't require extra time to maintain the LRU cache.\r\nThere is no other way to simulate 100+ different endpoint calls with the current benchmark suite.*\r\n\r\n```\r\n---- router-heavy ----\r\n✔ Results saved for head/router-heavy\r\n✔ Results saved for stable/router-heavy\r\nrouter-heavy throughput:\r\n{\r\n    \"significant\": \"***\",\r\n    \"equal\": false,\r\n    \"wins\": \"head\",\r\n    \"diff\": \"3086.8%\"\r\n}\r\n```","created_at":"2017-11-09T12:29:54Z","updated_at":"2018-02-05T22:58:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3afc2d851f885685427ba1b613b422a85ff423b0","assignee":null,"assignees":[],"requested_reviewers":[{"login":"yunong","id":1226256,"avatar_url":"https://avatars1.githubusercontent.com/u/1226256?v=4","gravatar_id":"","url":"https://api.github.com/users/yunong","html_url":"https://github.com/yunong","followers_url":"https://api.github.com/users/yunong/followers","following_url":"https://api.github.com/users/yunong/following{/other_user}","gists_url":"https://api.github.com/users/yunong/gists{/gist_id}","starred_url":"https://api.github.com/users/yunong/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yunong/subscriptions","organizations_url":"https://api.github.com/users/yunong/orgs","repos_url":"https://api.github.com/users/yunong/repos","events_url":"https://api.github.com/users/yunong/events{/privacy}","received_events_url":"https://api.github.com/users/yunong/received_events","type":"User","site_admin":false}],"requested_teams":[],"milestone":null,"commits_url":"https://api.github.com/repos/restify/node-restify/pulls/1561/commits","review_comments_url":"https://api.github.com/repos/restify/node-restify/pulls/1561/comments","review_comment_url":"https://api.github.com/repos/restify/node-restify/pulls/comments{/number}","comments_url":"https://api.github.com/repos/restify/node-restify/issues/1561/comments","statuses_url":"https://api.github.com/repos/restify/node-restify/statuses/5e096d0cbf0d1bd8a651165c66649e9450c1f4e0","head":{"label":"restify:feat/new-router","ref":"feat/new-router","sha":"5e096d0cbf0d1bd8a651165c66649e9450c1f4e0","user":{"login":"restify","id":6948699,"avatar_url":"https://avatars0.githubusercontent.com/u/6948699?v=4","gravatar_id":"","url":"https://api.github.com/users/restify","html_url":"https://github.com/restify","followers_url":"https://api.github.com/users/restify/followers","following_url":"https://api.github.com/users/restify/following{/other_user}","gists_url":"https://api.github.com/users/restify/gists{/gist_id}","starred_url":"https://api.github.com/users/restify/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/restify/subscriptions","organizations_url":"https://api.github.com/users/restify/orgs","repos_url":"https://api.github.com/users/restify/repos","events_url":"https://api.github.com/users/restify/events{/privacy}","received_events_url":"https://api.github.com/users/restify/received_events","type":"Organization","site_admin":false},"repo":{"id":1661758,"name":"node-restify","full_name":"restify/node-restify","owner":{"login":"restify","id":6948699,"avatar_url":"https://avatars0.githubusercontent.com/u/6948699?v=4","gravatar_id":"","url":"https://api.github.com/users/restify","html_url":"https://github.com/restify","followers_url":"https://api.github.com/users/restify/followers","following_url":"https://api.github.com/users/restify/following{/other_user}","gists_url":"https://api.github.com/users/restify/gists{/gist_id}","starred_url":"https://api.github.com/users/restify/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/restify/subscriptions","organizations_url":"https://api.github.com/users/restify/orgs","repos_url":"https://api.github.com/users/restify/repos","events_url":"https://api.github.com/users/restify/events{/privacy}","received_events_url":"https://api.github.com/users/restify/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/restify/node-restify","description":"The future of Node.js REST development","fork":false,"url":"https://api.github.com/repos/restify/node-restify","forks_url":"https://api.github.com/repos/restify/node-restify/forks","keys_url":"https://api.github.com/repos/restify/node-restify/keys{/key_id}","collaborators_url":"https://api.github.com/repos/restify/node-restify/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/restify/node-restify/teams","hooks_url":"https://api.github.com/repos/restify/node-restify/hooks","issue_events_url":"https://api.github.com/repos/restify/node-restify/issues/events{/number}","events_url":"https://api.github.com/repos/restify/node-restify/events","assignees_url":"https://api.github.com/repos/restify/node-restify/assignees{/user}","branches_url":"https://api.github.com/repos/restify/node-restify/branches{/branch}","tags_url":"https://api.github.com/repos/restify/node-restify/tags","blobs_url":"https://api.github.com/repos/restify/node-restify/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/restify/node-restify/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/restify/node-restify/git/refs{/sha}","trees_url":"https://api.github.com/repos/restify/node-restify/git/trees{/sha}","statuses_url":"https://api.github.com/repos/restify/node-restify/statuses/{sha}","languages_url":"https://api.github.com/repos/restify/node-restify/languages","stargazers_url":"https://api.github.com/repos/restify/node-restify/stargazers","contributors_url":"https://api.github.com/repos/restify/node-restify/contributors","subscribers_url":"https://api.github.com/repos/restify/node-restify/subscribers","subscription_url":"https://api.github.com/repos/restify/node-restify/subscription","commits_url":"https://api.github.com/repos/restify/node-restify/commits{/sha}","git_commits_url":"https://api.github.com/repos/restify/node-restify/git/commits{/sha}","comments_url":"https://api.github.com/repos/restify/node-restify/comments{/number}","issue_comment_url":"https://api.github.com/repos/restify/node-restify/issues/comments{/number}","contents_url":"https://api.github.com/repos/restify/node-restify/contents/{+path}","compare_url":"https://api.github.com/repos/restify/node-restify/compare/{base}...{head}","merges_url":"https://api.github.com/repos/restify/node-restify/merges","archive_url":"https://api.github.com/repos/restify/node-restify/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/restify/node-restify/downloads","issues_url":"https://api.github.com/repos/restify/node-restify/issues{/number}","pulls_url":"https://api.github.com/repos/restify/node-restify/pulls{/number}","milestones_url":"https://api.github.com/repos/restify/node-restify/milestones{/number}","notifications_url":"https://api.github.com/repos/restify/node-restify/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/restify/node-restify/labels{/name}","releases_url":"https://api.github.com/repos/restify/node-restify/releases{/id}","deployments_url":"https://api.github.com/repos/restify/node-restify/deployments","created_at":"2011-04-25T21:19:26Z","updated_at":"2018-02-05T15:20:25Z","pushed_at":"2018-02-05T21:46:41Z","git_url":"git://github.com/restify/node-restify.git","ssh_url":"git@github.com:restify/node-restify.git","clone_url":"https://github.com/restify/node-restify.git","svn_url":"https://github.com/restify/node-restify","homepage":"http://restify.com","size":3840,"stargazers_count":7772,"watchers_count":7772,"language":"JavaScript","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":856,"mirror_url":null,"archived":false,"open_issues_count":82,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":856,"open_issues":82,"watchers":7772,"default_branch":"master"}},"base":{"label":"restify:next","ref":"next","sha":"51bd49018f025e6bc72f087d0a732b05e9776c92","user":{"login":"restify","id":6948699,"avatar_url":"https://avatars0.githubusercontent.com/u/6948699?v=4","gravatar_id":"","url":"https://api.github.com/users/restify","html_url":"https://github.com/restify","followers_url":"https://api.github.com/users/restify/followers","following_url":"https://api.github.com/users/restify/following{/other_user}","gists_url":"https://api.github.com/users/restify/gists{/gist_id}","starred_url":"https://api.github.com/users/restify/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/restify/subscriptions","organizations_url":"https://api.github.com/users/restify/orgs","repos_url":"https://api.github.com/users/restify/repos","events_url":"https://api.github.com/users/restify/events{/privacy}","received_events_url":"https://api.github.com/users/restify/received_events","type":"Organization","site_admin":false},"repo":{"id":1661758,"name":"node-restify","full_name":"restify/node-restify","owner":{"login":"restify","id":6948699,"avatar_url":"https://avatars0.githubusercontent.com/u/6948699?v=4","gravatar_id":"","url":"https://api.github.com/users/restify","html_url":"https://github.com/restify","followers_url":"https://api.github.com/users/restify/followers","following_url":"https://api.github.com/users/restify/following{/other_user}","gists_url":"https://api.github.com/users/restify/gists{/gist_id}","starred_url":"https://api.github.com/users/restify/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/restify/subscriptions","organizations_url":"https://api.github.com/users/restify/orgs","repos_url":"https://api.github.com/users/restify/repos","events_url":"https://api.github.com/users/restify/events{/privacy}","received_events_url":"https://api.github.com/users/restify/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/restify/node-restify","description":"The future of Node.js REST development","fork":false,"url":"https://api.github.com/repos/restify/node-restify","forks_url":"https://api.github.com/repos/restify/node-restify/forks","keys_url":"https://api.github.com/repos/restify/node-restify/keys{/key_id}","collaborators_url":"https://api.github.com/repos/restify/node-restify/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/restify/node-restify/teams","hooks_url":"https://api.github.com/repos/restify/node-restify/hooks","issue_events_url":"https://api.github.com/repos/restify/node-restify/issues/events{/number}","events_url":"https://api.github.com/repos/restify/node-restify/events","assignees_url":"https://api.github.com/repos/restify/node-restify/assignees{/user}","branches_url":"https://api.github.com/repos/restify/node-restify/branches{/branch}","tags_url":"https://api.github.com/repos/restify/node-restify/tags","blobs_url":"https://api.github.com/repos/restify/node-restify/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/restify/node-restify/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/restify/node-restify/git/refs{/sha}","trees_url":"https://api.github.com/repos/restify/node-restify/git/trees{/sha}","statuses_url":"https://api.github.com/repos/restify/node-restify/statuses/{sha}","languages_url":"https://api.github.com/repos/restify/node-restify/languages","stargazers_url":"https://api.github.com/repos/restify/node-restify/stargazers","contributors_url":"https://api.github.com/repos/restify/node-restify/contributors","subscribers_url":"https://api.github.com/repos/restify/node-restify/subscribers","subscription_url":"https://api.github.com/repos/restify/node-restify/subscription","commits_url":"https://api.github.com/repos/restify/node-restify/commits{/sha}","git_commits_url":"https://api.github.com/repos/restify/node-restify/git/commits{/sha}","comments_url":"https://api.github.com/repos/restify/node-restify/comments{/number}","issue_comment_url":"https://api.github.com/repos/restify/node-restify/issues/comments{/number}","contents_url":"https://api.github.com/repos/restify/node-restify/contents/{+path}","compare_url":"https://api.github.com/repos/restify/node-restify/compare/{base}...{head}","merges_url":"https://api.github.com/repos/restify/node-restify/merges","archive_url":"https://api.github.com/repos/restify/node-restify/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/restify/node-restify/downloads","issues_url":"https://api.github.com/repos/restify/node-restify/issues{/number}","pulls_url":"https://api.github.com/repos/restify/node-restify/pulls{/number}","milestones_url":"https://api.github.com/repos/restify/node-restify/milestones{/number}","notifications_url":"https://api.github.com/repos/restify/node-restify/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/restify/node-restify/labels{/name}","releases_url":"https://api.github.com/repos/restify/node-restify/releases{/id}","deployments_url":"https://api.github.com/repos/restify/node-restify/deployments","created_at":"2011-04-25T21:19:26Z","updated_at":"2018-02-05T15:20:25Z","pushed_at":"2018-02-05T21:46:41Z","git_url":"git://github.com/restify/node-restify.git","ssh_url":"git@github.com:restify/node-restify.git","clone_url":"https://github.com/restify/node-restify.git","svn_url":"https://github.com/restify/node-restify","homepage":"http://restify.com","size":3840,"stargazers_count":7772,"watchers_count":7772,"language":"JavaScript","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":856,"mirror_url":null,"archived":false,"open_issues_count":82,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":856,"open_issues":82,"watchers":7772,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/restify/node-restify/pulls/1561"},"html":{"href":"https://github.com/restify/node-restify/pull/1561"},"issue":{"href":"https://api.github.com/repos/restify/node-restify/issues/1561"},"comments":{"href":"https://api.github.com/repos/restify/node-restify/issues/1561/comments"},"review_comments":{"href":"https://api.github.com/repos/restify/node-restify/pulls/1561/comments"},"review_comment":{"href":"https://api.github.com/repos/restify/node-restify/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/restify/node-restify/pulls/1561/commits"},"statuses":{"href":"https://api.github.com/repos/restify/node-restify/statuses/5e096d0cbf0d1bd8a651165c66649e9450c1f4e0"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"DonutEspresso"}}