Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timings: Tracks 'lookup', adds 'wait' time, fixes connection re-use #2566

Merged
merged 3 commits into from Mar 4, 2017
Merged

Timings: Tracks 'lookup', adds 'wait' time, fixes connection re-use #2566

merged 3 commits into from Mar 4, 2017

Conversation

nicjansma
Copy link
Contributor

@nicjansma nicjansma commented Feb 28, 2017

PR Checklist:

PR Description

Feedback from @mcorb in #2452 found a few items with the new .timings object.

Changes:

  1. The net 'lookup' event is now tracked, which is the correct event to track DNS lookup time.
  2. There is a new .timingStart property that is based on Date.now().
  3. The .timings.* timestamps are relative to .timingStart (using now()).
  4. The .timings object now only contains socket, lookup, connect, response and end (moving the durations to .timingPhases)
  5. .timings.start is no longer needed, since it will always in effect be 0.
  6. The other durations such as wait, dns, tcp, etc were moved to .timingPhases.
  7. A new .timingPhases.wait delta is added, which tracks the time from start->socket
  8. The .timingPhases.dns calculation is changed from start->socket to socket->lookup.
  9. Documentation was updated to be clearer about the handling of HTTP redirects and for all of the new properties above.
  10. For cases of connection re-use, the timings would have resulted in NaNs or negative numbers. This is resolved by assuming any events (such as lookup) that did not happen (due to re-use) are "filled in" using the timestamp of the previous phase (such as socket), resulting in a 0 ms delta.
  11. Fixes EventEmitter leak in 2.80 #2575 by not re-adding event listeners to Keep-Alive sockets (resulting in EventEmitter leak)

Here is an example of the current properties:

{ 
  elapsedTime: 143,                 // deprecated
  responseStartTime: 1488424737161, // deprecated
  timingStart: 1488424737018,       // Unix Epoch ms
  timings: {                        // relative to timingStart
     socket: 6.410719000000002,
     lookup: 7.299280000000001,
     connect: 46.287758000000004,
     response: 105.45501300000001,
     end: 142.975414 
  },
  timingPhases: {                   // durations
     wait: 6.410719000000002,
     dns: 0.8885609999999993,
     tcp: 38.988478,
     firstByte: 59.167255000000004,
     download: 37.52040099999999,
     total: 142.975414
  } 
}

Tests have been added.

@nicjansma
Copy link
Contributor Author

@Huachao and @FredKSchott would appreciate you taking a look!

if (!self.timings.connect) {
self.timings.connect = self.timings.lookup
}
if (!self.timings.response) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: in which case self.timings.response is blank, or response event is not triggered?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it's even possible, but I added it here for consistency and to protect against edge cases.

README.md Outdated
- `response`: Timestamp when the [`http`](https://nodejs.org/api/http.html#http_event_response) module's `response` event fires. This happens when the first bytes are received from the server.
- `end`: Timestamp when the last bytes of the response are received.
- `dns`: Duration of DNS lookup (`timings.socket` - `timings.start`)
- `time` - If `true`, the request-response cycle (including all redirects) is timed at millisecond resolution, and the result provided on the response's `elapsedTime` property. The start time of the request (in Unix Epoch milliseconds via `Date`) is saved as `timingStart`. The `responseStartTime` property is also available to indicate the timestamp when the response begins. In addition, there is a `timings` object available with timestamps in millisecond resolution relative to `timingStart`. If there were redirects, the properties reflect the timings of the final request in the redirect chain:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's important to emphasize the elapsedTime and responseStartTime is deprecated in README

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I've reorganized the description here a bit to be a list of all properties added.

t.equal((res.timings.start > 0), true)
t.equal((res.timings.socket >= res.timings.start), true)
t.equal((res.timings.socket >= 0), true)
t.equal((res.timings.lookup >= res.timings.socket), true)
t.equal((res.timings.connect >= res.timings.socket), true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

res.timing.lookup

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch.

@FredKSchott
Copy link
Contributor

Thanks for the work @nicjansma, I'll be mostly offline until Monday but would love to take a look at this once back

README.md Outdated
- `timings` Contains event timestamps in millisecond resolution relative to `timingStart`. If there were redirects, the properties reflect the timings of the final request in the redirect chain:
- `socket` Relative timestamp when the [`http`](https://nodejs.org/api/http.html#http_event_socket) module's `socket` event fires. This happens when the socket is assigned to the request.
- `lookup` Relative timestamp when the [`net`](https://nodejs.org/api/net.html#net_event_lookup) module's `lookup` event fires. This happens when the DNS has been resolved.
- `connect`: Relative timestamp when the [`http`](https://nodejs.org/api/http.html#http_event_connect) module's `connect` event fires. This happens when the server acknowledges the TCP connection.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the connect event is not the one in http module, it's the one in net of Socket class, the doc url should be https://nodejs.org/api/net.html#net_event_connect

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch, fixed

@nicjansma
Copy link
Contributor Author

@mikeal Some fixes in here for #2575

@mikeal
Copy link
Member

mikeal commented Mar 4, 2017

Once CI passes I would like to get this in because it fixes a leak introduced in the last release. Is anyone still in the middle of reviews that would object?

@mikeal
Copy link
Member

mikeal commented Mar 4, 2017

Wow, there's a big falloff in code coverage.

@nicjansma
Copy link
Contributor Author

-0.35% overall. It seems like it's just due to 4 lines in the new patch that aren't run (which cover error conditions):

https://codecov.io/gh/request/request/compare/667e923d8d51a0f0fb4c66c91d94a40f3d3e575a...32232d91f86f16b20d76f21363d7ae4a22a0af45/diff

If you're worried about it, I can see if I can create test cases for those scenarios in a followup PR (though tomorrow at the earliest).

@mikeal
Copy link
Member

mikeal commented Mar 4, 2017

Oh i see, was reading that wrong. Merging this to fix the bug. Would love a followup with more tests :)

@mikeal mikeal merged commit 2e70b74 into request:master Mar 4, 2017
@nicjansma nicjansma mentioned this pull request Mar 9, 2017
3 tasks
@nicjansma
Copy link
Contributor Author

@mikeal KeepAlive test here: #2590

Copy link
Member

@mikeal mikeal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

EventEmitter leak in 2.80
4 participants