-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
http2: add diagnostics channel 'http2.server.stream.start' #58449
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
'use strict'; | ||
|
||
const common = require('../common'); | ||
if (!common.hasCrypto) | ||
common.skip('missing crypto'); | ||
|
||
// This test ensures that the built-in HTTP/2 diagnostics channels are reporting | ||
// the diagnostics messages for the 'http2.server.stream.start' channel only | ||
// after the 'http2.server.stream.created' channel. | ||
|
||
const Countdown = require('../common/countdown'); | ||
const assert = require('assert'); | ||
const dc = require('diagnostics_channel'); | ||
const http2 = require('http2'); | ||
|
||
const serverHttp2StreamCreationCount = 2; | ||
|
||
const map = {}; | ||
|
||
dc.subscribe('http2.server.stream.created', common.mustCall(({ stream, headers }) => { | ||
map[stream.id] = { ...map[stream.id], 'createdTime': process.hrtime.bigint() }; | ||
}, serverHttp2StreamCreationCount)); | ||
|
||
dc.subscribe('http2.server.stream.start', common.mustCall(({ stream, headers }) => { | ||
map[stream.id] = { ...map[stream.id], 'startTime': process.hrtime.bigint() }; | ||
}, serverHttp2StreamCreationCount)); | ||
|
||
const server = http2.createServer(); | ||
server.on('stream', common.mustCall((stream) => { | ||
stream.respond(); | ||
stream.end(); | ||
|
||
stream.pushStream({}, common.mustSucceed((pushStream) => { | ||
pushStream.respond(); | ||
pushStream.end(); | ||
})); | ||
})); | ||
|
||
server.listen(0, common.mustCall(() => { | ||
const port = server.address().port; | ||
const client = http2.connect(`http://localhost:${port}`); | ||
|
||
const countdown = new Countdown(serverHttp2StreamCreationCount, () => { | ||
client.close(); | ||
server.close(); | ||
|
||
const timings = Object.values(map); | ||
assert.strictEqual(timings.length, serverHttp2StreamCreationCount); | ||
|
||
for (const { createdTime, startTime } of timings) { | ||
assert.ok(createdTime < startTime); | ||
} | ||
}); | ||
|
||
const stream = client.request({}); | ||
stream.on('response', common.mustCall(() => { | ||
countdown.dec(); | ||
})); | ||
|
||
client.on('stream', common.mustCall((pushStream) => { | ||
pushStream.on('push', common.mustCall(() => { | ||
countdown.dec(); | ||
})); | ||
})); | ||
})); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
'use strict'; | ||
|
||
const common = require('../common'); | ||
if (!common.hasCrypto) | ||
common.skip('missing crypto'); | ||
|
||
// This test ensures that the built-in HTTP/2 diagnostics channels are reporting | ||
// the diagnostics messages for the 'http2.server.stream.start' channel when | ||
// ServerHttp2Streams are started by both: | ||
// - in response to an incoming 'stream' event from the client | ||
// - the server calling ServerHttp2Stream#pushStream() | ||
|
||
const Countdown = require('../common/countdown'); | ||
const assert = require('assert'); | ||
const dc = require('diagnostics_channel'); | ||
const http2 = require('http2'); | ||
const { Duplex } = require('stream'); | ||
|
||
const serverHttp2StreamCreationCount = 2; | ||
|
||
dc.subscribe('http2.server.stream.start', common.mustCall(({ stream, headers }) => { | ||
// Since ServerHttp2Stream is not exported from any module, this just checks | ||
// if the stream is an instance of Duplex and the constructor name is | ||
// 'ServerHttp2Stream'. | ||
assert.ok(stream instanceof Duplex); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note that exposing internals makes it hard to ever move this out of experimental at some point in time in future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
assert.strictEqual(stream.constructor.name, 'ServerHttp2Stream'); | ||
assert.ok(headers && !Array.isArray(headers) && typeof headers === 'object'); | ||
}, serverHttp2StreamCreationCount)); | ||
|
||
const server = http2.createServer(); | ||
server.on('stream', common.mustCall((stream) => { | ||
stream.respond(); | ||
stream.end(); | ||
|
||
stream.pushStream({}, common.mustSucceed((pushStream) => { | ||
pushStream.respond(); | ||
pushStream.end(); | ||
})); | ||
})); | ||
|
||
server.listen(0, common.mustCall(() => { | ||
const port = server.address().port; | ||
const client = http2.connect(`http://localhost:${port}`); | ||
|
||
const countdown = new Countdown(serverHttp2StreamCreationCount, () => { | ||
client.close(); | ||
server.close(); | ||
}); | ||
|
||
const stream = client.request({}); | ||
stream.on('response', common.mustCall(() => { | ||
countdown.dec(); | ||
})); | ||
|
||
client.on('stream', common.mustCall((pushStream) => { | ||
pushStream.on('push', common.mustCall(() => { | ||
countdown.dec(); | ||
})); | ||
})); | ||
})); |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this one comes always together with
http2.server.stream.created
. In one case there is anextTick
in between.Which use case is solved by this extra event?
If the timing between created and start is important we should test the timing stays as expected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The distinction between the two is that 'created' is for when the stream has just been created but 'start' is where the application starts using the stream. Here, 'start' gets called in the nextTick because that's where the pushStream callback gets invoked, where the user code can start using the push stream. I have added a test for the timings, PTAL @Flarna .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But they always come in pairs, sometimes with a
nextTick
inbetween, sometimes not.But there is no case where a create is not immediately followed by a start right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's right. It could be useful to debug any performance issues that might be stemming from the blocking code that runs after
pushStream()
get called but before the callback is fired.