diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-15 08:28:43 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-15 08:29:45 +0200 |
| commit | bbbb7461d19e611e6fab3f24edd5f8e0d2d45b1e (patch) | |
| tree | bee4b9e07bafb2810f0e2cc2db4fb34e7154b2d4 /internal/clients | |
| parent | d89b9e6760e2aadf9779faa6f23678f67c731e1e (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.go | 23 |
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) |
