Skip to content

grpc: disable and document overrides of OS default TCP keepalive by Go #6672

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

Merged
merged 7 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions dialoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ func WithTimeout(d time.Duration) DialOption {
// connections. If FailOnNonTempDialError() is set to true, and an error is
// returned by f, gRPC checks the error's Temporary() method to decide if it
// should try to reconnect to the network address.
//
// Note: Go overrides the OS defaults for TCP keepalive interval to 15s.
// To retain the OS defaults, pass in a custom dialer with KeepAlive set to a negative duration.
func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.Dialer = f
Expand Down
7 changes: 6 additions & 1 deletion examples/helloworld/greeter_server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"fmt"
"log"
"net"
"time"

"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
Expand All @@ -47,7 +48,11 @@ func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloRe

func main() {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
// ListenConfig allows options to be passed to the listener.
var lc net.ListenConfig
// Setting KeepAlive to -1 allows the listener to retain OS default TCP keep-alive interval.
lc.KeepAlive = time.Duration(-1)
lis, err := lc.Listen(context.Background(), "tcp", fmt.Sprintf(":%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/transport/http2_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error
if networkType == "tcp" && useProxy {
return proxyDial(ctx, address, grpcUA)
}
return (&net.Dialer{}).DialContext(ctx, networkType, address)
return (&net.Dialer{KeepAlive: time.Duration(-1)}).DialContext(ctx, networkType, address)
}

func isTemporary(err error) bool {
Expand Down
6 changes: 6 additions & 0 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,12 @@ func (l *listenSocket) Close() error {
// Serve returns when lis.Accept fails with fatal errors. lis will be closed when
// this method returns.
// Serve will return a non-nil error unless Stop or GracefulStop is called.
//
// Note: Go overrides the OS defaults for TCP keepalive interval to 15s.
// To retain the OS defaults, you will need to create a net.ListenConfig with the
// KeepAlive parameter set to a negative value and use the Listen method on it to create
// the net.Listener to pass to this function.
// See https://github.com/grpc/grpc-go/blob/master/examples/helloworld/greeter_client/main.go#L51
func (s *Server) Serve(lis net.Listener) error {
s.mu.Lock()
s.printf("serving")
Expand Down