-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
transport: Send RST stream from the server when deadline expires #8071
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #8071 +/- ##
==========================================
+ Coverage 82.36% 82.49% +0.13%
==========================================
Files 387 388 +1
Lines 39065 39049 -16
==========================================
+ Hits 32174 32214 +40
+ Misses 5562 5538 -24
+ Partials 1329 1297 -32
|
805939c
to
6dda22e
Compare
806c418
to
fca2350
Compare
fca2350
to
a97949e
Compare
internal/grpctest/grpctest.go
Outdated
} | ||
|
||
// Teardown performs a leak check. | ||
func (Tester) Teardown(t *testing.T) { | ||
leakcheck.CheckTrackingBufferPool() | ||
leakcheck.CheckTimers(5 * time.Second) |
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.
This is additive with the 10s for checking goroutines. It might be nice to pass a context (or timer) to both of these instead, so they can share the 10s timeout?
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.
Nice idea, changed.
internal/leakcheck/leakcheck.go
Outdated
|
||
originalTimeAfterFunc func(time.Duration, func()) internal.Timer | ||
mu sync.Mutex | ||
bufferCount int |
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.
Delete
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.
Oops, removed.
internal/leakcheck/leakcheck.go
Outdated
type timerFactory struct { | ||
logger Logger | ||
|
||
originalTimeAfterFunc func(time.Duration, func()) internal.Timer |
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.
Is there any need for this? As opposed to just directly calling time.AfterFunc
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.
I was thinking about a future scenarios when subtests and outer tests both start leak checks. Having the previously set function would allow wrapping the outer tests function. The global globalTimerTracker
would still prevent this from working.
Removed this field. This use case can be addressed if/when it arises.
internal/leakcheck/leakcheck.go
Outdated
// not all timers were cancelled or executed. It is invalid to invoke this | ||
// function without previously having invoked SetTimerTracker. | ||
func CheckTimers(timeout time.Duration) { | ||
// Reset the internal function. |
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.
This happens at the end?
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, moved the comment to the end.
internal/transport/http2_client.go
Outdated
// of this cancellation. Alter the status code accordingly. | ||
// of this cancellation. Alter the status code accordingly. |
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.
Please revert.
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 seemed like a harmless typo fix, but I’ve reverted it as requested.
internal/leakcheck/leakcheck.go
Outdated
// SetTimerTracker replaces internal.TimerAfterFunc with a one that tracks | ||
// timer creations. CheckTimers should then be invoked at the end of the test to | ||
// validate that all timers created have either executed or are cancelled. | ||
func SetTimerTracker(logger Logger) { |
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.
Can you add a test for this functionality?
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.
Didn't notice that there were tests for this file. Added a test now.
internal/transport/http2_server.go
Outdated
s.deadlineTimerCancel = func() { | ||
timer.Stop() | ||
} |
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.
s.deadlineTimerCancel = func() { | |
timer.Stop() | |
} | |
s.deadlineTimerCancel = timer.Stop |
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.
Changed to use the cancel
field on ServerStream
. cancel
is always set to a non-nil value, so this issue is solved.
internal/transport/http2_server.go
Outdated
if s.deadlineTimerCancel != nil { | ||
s.deadlineTimerCancel() | ||
} |
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.
Should we make sure this is always a valid function so we can just call it without the nil check?
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.
Changed to use the existing cancel
field.
oldState := s.swapState(streamDone) | ||
if oldState == streamDone { |
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.
Was this a bug before? Or did we have something that prevented it? Or was the code tolerant of multiple calls?
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.
Going through the references, it seems like closeStream
can be called concurrently. The race seems rare because the call to deleteStream
below removes the stream from the activeStreams
map of the server. Most code paths try to get the stream from activeStreams
, so they can't call closeStream
anymore.
When the function does execute multiple times, the only symptoms seem to be overcounting of channelz metrics here
grpc-go/internal/transport/http2_server.go
Lines 1287 to 1293 in 8528f43
if channelz.IsOn() { | |
if eosReceived { | |
t.channelz.SocketMetrics.StreamsSucceeded.Add(1) | |
} else { | |
t.channelz.SocketMetrics.StreamsFailed.Add(1) | |
} | |
} |
and possibly sending multiple RST streams to the peer because of enqueuing a cleanupStream
event in the controlBuf
.
internal/transport/server_stream.go
Outdated
cancel context.CancelFunc // invoked at the end of stream to cancel ctx. | ||
deadlineTimerCancel func() // Invoked at the end of stream. |
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.
Do we always call cancel
? Can we piggyback the timer cancellation with it if so?
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 we do, changed to use cancel
.
Fixes: #2886
This PR makes the server cancel an RPC when it sees the deadline expiring instead of waiting forn the client to cancel the stream.
RELEASE NOTES: