-
Notifications
You must be signed in to change notification settings - Fork 350
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
skipper: support http2 over cleartext TCP (h2c) #2480
base: master
Are you sure you want to change the base?
Conversation
bbd6747
to
ff6f242
Compare
return err | ||
} else { | ||
listener = snet.NewShutdownListener(l) |
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 will also wait for hijacked connection when h2c is not enabled.
Need to think if there is any downside to it and maybe add a test.
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.
Does it work with upgrade connections like websocket?
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.
https://pkg.go.dev/net/http#Server.Shutdown
Shutdown does not attempt to close nor wait for hijacked connections such as WebSockets. The caller of Shutdown should separately notify such long-lived connections of shutdown and wait for them to close, if desired.
This is useful by itself to track hijacked connections (and maybe it should forcibly close and log remaining after timeout as currently Skipper will be killed after termination grace period (assuming cluster ingress mode)).
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 create a follow up issue for that?
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 plan to check this before we merge.
} | ||
|
||
func (l *ShutdownListener) Shutdown(ctx context.Context) error { | ||
ticker := time.NewTicker(500 * time.Millisecond) |
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.
Why so often?
I would not ask if it was 1s.
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 it? Check out http.Server.Shutdown - it starts with 1ms and doubles until reaches 500ms, here I decided not to over-complicate things.
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.
Oh that's way too often
net/shutdown_listener.go
Outdated
defer ticker.Stop() | ||
for { | ||
n := l.activeConns.Load() | ||
log.Debugf("ShutdownListener Shutdown: %d connections", n) |
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.
We should have it as Infof and degrade if it's not needed. It's great to observe shutdown for a while.
net/shutdown_listener.go
Outdated
|
||
func (l *ShutdownListener) registerConn() { | ||
n := l.activeConns.Add(1) | ||
log.Debugf("ShutdownListener registerConn: %d connections", n) |
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 need this?
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.
For debugging, it does not hurt but I can remove.
net/shutdown_listener.go
Outdated
|
||
func (l *ShutdownListener) unregisterConn() { | ||
n := l.activeConns.Add(-1) | ||
log.Debugf("ShutdownListener unregisterConn: %d connections", n) |
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 need this?
Maybe better expose a metric.
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 for debugging, IMO does not hurt
return err | ||
} else { | ||
listener = snet.NewShutdownListener(l) |
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.
Does it work with upgrade connections like websocket?
} | ||
|
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.
add also:
else {log.Info("shutdown done")}
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.
We have log.Infof("done.") at the end
testServerShutdown(t, o, protoH2C, testGracefulConnectionShutdown) | ||
|
||
for i := 0; i < connectionShutdownChecks; i++ { | ||
require.NoError(t, <-errc, "Expected to receive GOAWAY frame on shutdown") |
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 this not check that we received a GOAWAY frame?
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.
If we did not receive it will fail with EOF error
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.
So we have another EOF case
Works around golang/go#26682 by introducing ShutdownListener that tracks active connections and implements graceful shutdown. For #1253 Signed-off-by: Alexander Yastrebov <[email protected]>
ff6f242
to
3a9dcac
Compare
How to play with it:
then e.g. create h2c connection via patched h2i tool:
terminate skipper
and observe shutdown logs:
and h2i logs:
With curl
|
return &http.Client{ | ||
Transport: &http2.Transport{ | ||
// allow http scheme | ||
AllowHTTP: true, |
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 guess we should do the same for skipper's net.Client.
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.
Need to check if it continues to support http1 though. Otherwise we may think either about supporting h2c scheme for endpoints like h2c://192.168.0.1
or have a filter that'd configure backend transport/roundtripper.
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.
That would be even better to support a scheme
Works around golang/go#26682 by introducing ShutdownListener that tracks active connections and implements graceful shutdown.
For #1253