diff --git a/docs/taproot-assets/examples/basic-price-oracle/main.go b/docs/taproot-assets/examples/basic-price-oracle/main.go index 83609fc7..4fde54c0 100644 --- a/docs/taproot-assets/examples/basic-price-oracle/main.go +++ b/docs/taproot-assets/examples/basic-price-oracle/main.go @@ -29,6 +29,7 @@ import ( "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/keepalive" ) const ( @@ -455,11 +456,44 @@ func main() { log.Fatalf("Failed to generate TLS certificate: %v", err) } - // Create the gRPC server with TLS + // Configure server-side keepalive parameters. These settings ensure the + // server actively probes client connection health and allows long-lived + // idle connections. + serverKeepalive := keepalive.ServerParameters{ + // Ping clients after 1 minute of inactivity. + Time: time.Minute, + + // Wait 20 seconds for ping response. + Timeout: 20 * time.Second, + + // Allow connections to stay idle for 24 hours. The active + // pinging mechanism (via Time parameter) handles health + // checking, so we don't need aggressive idle timeouts. + MaxConnectionIdle: time.Hour * 24, + } + + // Configure client keepalive enforcement policy. This tells the server + // how to handle client keepalive pings. + clientKeepalive := keepalive.EnforcementPolicy{ + // Allow client to ping even when there are no active RPCs. + // This is critical for long-lived connections with infrequent + // price queries. + PermitWithoutStream: true, + + // Prevent abusive clients from pinging too frequently (DoS + // protection). + MinTime: 5 * time.Second, + } + + // Create the gRPC server with TLS and keepalive configuration. transportCredentials := credentials.NewTLS(&tls.Config{ Certificates: []tls.Certificate{tlsCert}, }) - backendService := grpc.NewServer(grpc.Creds(transportCredentials)) + backendService := grpc.NewServer( + grpc.Creds(transportCredentials), + grpc.KeepaliveParams(serverKeepalive), + grpc.KeepaliveEnforcementPolicy(clientKeepalive), + ) err = startService(backendService) if err != nil { diff --git a/docs/taproot-assets/release-notes/release-notes-0.7.0.md b/docs/taproot-assets/release-notes/release-notes-0.7.0.md index 92eba525..1710804f 100644 --- a/docs/taproot-assets/release-notes/release-notes-0.7.0.md +++ b/docs/taproot-assets/release-notes/release-notes-0.7.0.md @@ -63,6 +63,18 @@ dirty. This issue has been resolved, and the behavior is now consistent across all database backend types. +- [Fixed "connection reset by peer" errors in RFQ price oracle + connections](https://github.com/lightninglabs/taproot-assets/pull/1834) by + implementing comprehensive bidirectional gRPC keepalive configuration. The + issue occurred when connections sat idle between RFQ price queries and were + silently closed by the network layer or server timeout, causing the first + payment attempt after an idle period to fail. The fix adds client-side + keepalive pings every 30 seconds and extends the server's idle connection + timeout from 2 minutes to 24 hours, while enabling active health checking on + both sides. This ensures connections remain alive during infrequent RFQ + operations and any network issues are detected promptly rather than + discovered only when the next RPC fails. + # New Features ## Functional Enhancements