diff --git a/agent/internal/grpc/client.go b/agent/internal/grpc/client.go index 19a1363..3a00db3 100644 --- a/agent/internal/grpc/client.go +++ b/agent/internal/grpc/client.go @@ -11,6 +11,7 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/encoding" + "google.golang.org/grpc/keepalive" ) func init() { @@ -26,7 +27,15 @@ func New(serverURL string, useTLS bool) (*Client, error) { serverURL = strings.TrimPrefix(serverURL, "https://") serverURL = strings.TrimPrefix(serverURL, "http://") - var dialOpts []grpc.DialOption + // Send a ping every 30s so proxies with a 60s idle timeout don't kill the + // long-lived CommandStream when no commands are flowing. + dialOpts := []grpc.DialOption{ + grpc.WithKeepaliveParams(keepalive.ClientParameters{ + Time: 30 * time.Second, + Timeout: 10 * time.Second, + PermitWithoutStream: false, + }), + } if useTLS { tlsCfg := &tls.Config{ diff --git a/server/internal/grpc/server.go b/server/internal/grpc/server.go index f2d0f1f..d601aaf 100644 --- a/server/internal/grpc/server.go +++ b/server/internal/grpc/server.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "net" + "time" "github.com/mrhid6/vantage/server/internal/grpc/pb" "github.com/mrhid6/vantage/server/internal/models" @@ -12,6 +13,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/encoding" + "google.golang.org/grpc/keepalive" "google.golang.org/grpc/status" ) @@ -147,7 +149,20 @@ func StartGRPC(port int) error { return fmt.Errorf("failed to listen: %w", err) } - s := grpc.NewServer() + s := grpc.NewServer( + // Accept client keepalive pings as fast as every 20s so the 30s agent + // ping interval is always within the allowed window. + grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{ + MinTime: 20 * time.Second, + PermitWithoutStream: false, + }), + grpc.KeepaliveParams(keepalive.ServerParameters{ + // Server also pings the client after 45s of inactivity so both + // sides can detect a dead connection without waiting for a timeout. + Time: 45 * time.Second, + Timeout: 10 * time.Second, + }), + ) pb.RegisterVantageServer(s, &vantageServer{}) log.Printf("gRPC server listening on :%d", port)