Skip to content

feat: Connection Pooling and Session Keep-Alives #83

@JacobCallahan

Description

@JacobCallahan

Summary

Introduce a session management layer—connection pooling and keep-alive heartbeats—to reduce per-operation overhead for high-frequency automation workloads.

Motivation

Each Connection context manager currently tears down and re-establishes the SSH session on exit. When running dozens or hundreds of small commands in a loop, the repeated TCP handshake + key-exchange cost dominates wall-clock time. Additionally, long-idle sessions are silently dropped by firewalls and cloud NAT gateways, causing unexpected BrokenPipe / socket closed errors.

Proposed Design

Connection Pool

Provide a ConnectionPool (and AsyncConnectionPool) that vends pre-authenticated sessions from a fixed-size pool, re-authenticating only when a slot is empty or the underlying session has died.

from hussh import ConnectionPool

pool = ConnectionPool(
    host="myserver.example.com",
    username="deploy",
    password="...",
    max_connections=10,
)

# Each call borrows a ready session from the pool
with pool.connection() as conn:
    result = conn.execute("uptime")

Session Keep-Alives

Add keepalive_interval and keepalive_count_max parameters to Connection / AsyncConnection to send periodic SSH-level heartbeat packets and keep NAT mappings alive.

conn = Connection(
    "myserver.example.com",
    username="user",
    password="...",
    keepalive_interval=30,   # send a heartbeat every 30 s
    keepalive_count_max=3,   # give up after 3 unanswered heartbeats
)

Implementation Notes

  • Pooling: Maintain an internal queue of open Session objects. On borrow, validate liveness (e.g., send a no-op channel request); on return, reset channel state and re-enqueue. Thread-safety is required for the sync pool; asyncio-safety for the async pool.
  • Keep-Alives: Map to ssh2::Session::set_keepalive (sync) and the equivalent russh API (async). A background Tokio task can drive the async heartbeat loop.
  • Connection errors during borrow should transparently create a replacement session rather than surfacing to the caller.

Acceptance Criteria

  • ConnectionPool / AsyncConnectionPool classes with configurable pool size
  • keepalive_interval / keepalive_count_max parameters on Connection and AsyncConnection
  • Pool is thread-safe (sync) / coroutine-safe (async)
  • Tests covering pool exhaustion, session recovery after drop, and keep-alive behaviour
  • Benchmarks demonstrating latency improvement for multi-command workloads
  • Documentation updated

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions