Context
Inspired by the Cranker Connector's sliding window of pre-established connections, vyx should maintain a pool of ready-to-use UDS connections per worker to eliminate connection setup latency on the hot path.
Cranker's key insight: each connector keeps N connections open and waiting before a request arrives. When one connection is consumed by a request, a new one is opened immediately to maintain the pool size. This ensures the first byte of a request never waits for connection establishment.
The Problem
Currently, the uds.Transport in vyx creates a new Unix Domain Socket connection for each request on-demand:
Request arrives
│
▼
transport.Send()
│
▼
net.Dial("/tmp/vyx/node:api.sock") ← connection setup latency here
│
▼
write IPC frame
│
▼
read response
Under load (many concurrent requests), this creates:
- Repeated connection setup overhead
- File descriptor exhaustion risk
- No reuse of idle connections
Proposed Solution
Implement a connection pool with a sliding window per worker ID inside uds.Transport.
Pool Behaviour
Pool for "node:api" (window size = 4)
[■ ready][■ ready][■ ready][■ ready] ← all pre-connected
│
Request arrives, acquires slot
│
[■ ready][■ ready][□ in-use][■ ready]
│
Immediately open a new connection
│
[■ ready][■ ready][□ in-use][■ ready][■ new]
│
Request completes, connection returned or closed
│
[■ ready][■ ready][■ ready][■ ready] ← window maintained
Configuration
ipc:
socket_dir: /tmp/vyx
pool:
min_idle: 2 # minimum pre-established connections per worker
max_size: 16 # maximum total connections per worker
idle_timeout: 30s # close connections idle longer than this
Interface changes
// ConnectionPool manages a sliding window of UDS connections for a single worker.
type ConnectionPool struct {
workerID string
socketPath string
minIdle int
maxSize int
idle chan net.Conn
mu sync.Mutex
}
func (p *ConnectionPool) Acquire(ctx context.Context) (net.Conn, error)
func (p *ConnectionPool) Release(conn net.Conn)
func (p *ConnectionPool) replenish() // called after each Acquire to maintain minIdle
func (p *ConnectionPool) Close() error
Expected Impact
| Scenario |
Before |
After |
| First request to worker |
~0.5ms (dial) + IPC |
~0.05ms (pool) + IPC |
| 100 concurrent requests |
100 dials |
max_size dials, rest queue |
| Worker restart |
all connections invalid |
pool detects + reconnects |
Acceptance Criteria
References
Context
Inspired by the Cranker Connector's sliding window of pre-established connections,
vyxshould maintain a pool of ready-to-use UDS connections per worker to eliminate connection setup latency on the hot path.Cranker's key insight: each connector keeps N connections open and waiting before a request arrives. When one connection is consumed by a request, a new one is opened immediately to maintain the pool size. This ensures the first byte of a request never waits for connection establishment.
The Problem
Currently, the
uds.Transportinvyxcreates a new Unix Domain Socket connection for each request on-demand:Under load (many concurrent requests), this creates:
Proposed Solution
Implement a connection pool with a sliding window per worker ID inside
uds.Transport.Pool Behaviour
Configuration
Interface changes
Expected Impact
Acceptance Criteria
ConnectionPoolimplemented incore/infrastructure/ipc/udsuds.TransportusesConnectionPoolper registered workermin_idlepre-established connections at all timesidle_timeoutare closed and replacedmax_sizecap is respected; excess requests wait with context cancellation supportipc.poolblock added tovyx.yamlschemago test -bench) comparing pooled vs. non-pooled throughputReferences
core/infrastructure/ipc/uds/transport.go— current UDS transport