summaryrefslogtreecommitdiff
path: root/internal/clients
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-15 08:28:43 +0200
committerPaul Buetow <paul@buetow.org>2026-02-15 08:29:45 +0200
commitbbbb7461d19e611e6fab3f24edd5f8e0d2d45b1e (patch)
treebee4b9e07bafb2810f0e2cc2db4fb34e7154b2d4 /internal/clients
parentd89b9e6760e2aadf9779faa6f23678f67c731e1e (diff)
refactor: implement context-aware network dialing
Modernize network dialing to use Go's context-aware patterns for better cancellation support and connection reliability. Changes: - Update Go version from 1.24 to 1.25 in go.mod - Replace ssh.Dial with net.Dialer.DialContext + ssh.NewClientConn for SSH client connections in serverconnection.go - Add TCP KeepAlive (30s) for SSH connection health monitoring - Implement context-aware dialing for SSH agent connections in ssh.go - Improve error messages to distinguish dial vs SSH handshake failures - Update AGENTS.md with integration test requirements Benefits: - Context cancellation now properly affects connection establishment - TCP KeepAlive prevents silent connection failures - Better integration with Go's cancellation patterns - Improved reliability for distributed systems All integration tests pass with race detection enabled. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'internal/clients')
-rw-r--r--internal/clients/connectors/serverconnection.go23
1 files changed, 21 insertions, 2 deletions
diff --git a/internal/clients/connectors/serverconnection.go b/internal/clients/connectors/serverconnection.go
index 34d3997..d114d06 100644
--- a/internal/clients/connectors/serverconnection.go
+++ b/internal/clients/connectors/serverconnection.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
+ "net"
"strconv"
"strings"
"time"
@@ -135,10 +136,28 @@ func (c *ServerConnection) dial(ctx context.Context, cancel context.CancelFunc,
address := fmt.Sprintf("%s:%d", c.hostname, c.port)
dlog.Client.Debug(c.server, "Dialing into the connection", address)
- client, err := ssh.Dial("tcp", address, c.config)
+ // Use context-aware dialing to enable proper cancellation during connection establishment.
+ // TCP KeepAlive (30s) prevents silent connection failures on long-lived connections.
+ dialer := &net.Dialer{
+ Timeout: c.config.Timeout, // Use the SSH config timeout (2 seconds)
+ KeepAlive: 30 * time.Second, // Standard Go default for connection health monitoring
+ }
+
+ // Establish TCP connection with context support for cancellation
+ conn, err := dialer.DialContext(ctx, "tcp", address)
+ if err != nil {
+ return fmt.Errorf("failed to dial TCP connection to %s: %w", address, err)
+ }
+
+ // Perform SSH handshake over the established TCP connection
+ sshConn, chans, reqs, err := ssh.NewClientConn(conn, address, c.config)
if err != nil {
- return fmt.Errorf("failed to dial SSH connection to %s: %w", address, err)
+ conn.Close()
+ return fmt.Errorf("SSH handshake failed for %s: %w", address, err)
}
+
+ // Create SSH client from the connection components
+ client := ssh.NewClient(sshConn, chans, reqs)
defer client.Close()
return c.session(ctx, cancel, client, throttleCh)