Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
38 changes: 36 additions & 2 deletions docs/taproot-assets/examples/basic-price-oracle/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/keepalive"
)

const (
Expand Down Expand Up @@ -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 {
Expand Down
12 changes: 12 additions & 0 deletions docs/taproot-assets/release-notes/release-notes-0.7.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down