Skip to content

Proposal: avoid closing pooled connections on context deadline when response can be drained #3808

@jronak

Description

@jronak

Expected Behavior

When ContextTimeoutEnabled is enabled and a caller context deadline expires, go-redis should be able to return ctx.Err() without always closing the underlying pooled connection, as long as the connection can be brought back into RESP sync safely.

Current Behavior

Context cancellation/deadline errors are treated as bad connection errors. If a command times out via context, the connection is removed from the pool and closed.

This is safe, but expensive for Redis over TLS because frequent context deadlines can cause frequent TCP/TLS reconnects.

Possible Solution

Add an opt-in mode, for example:

DrainOnContextTimeout bool
ContextTimeoutDrainTimeout time.Duration

Behavior:

  1. Return ctx.Err() to the caller when the caller context expires.
  2. Keep the connection out of the pool.
  3. Continue reading/discarding the outstanding Redis response under a bounded internal timeout.
  4. If drain succeeds, return the connection to the pool.
  5. If drain fails or times out, close/remove the connection as today.

Steps to Reproduce

  1. Use go-redis with ContextTimeoutEnabled: true.
  2. Connect to Redis over TLS.
  3. Run commands with short context deadlines.
  4. Observe that timed-out operations close pooled connections and trigger new TLS handshakes.

Context (Environment)

  • go-redis version: v9 / main
  • Redis version: Redis 7+
  • Use case: short caller deadlines under load

Detailed Description

The goal is not to ignore caller cancellation. The user-facing command should still finish with context.DeadlineExceeded / context.Canceled when the caller context expires.

The proposed change is only about what happens to the already-written command's connection after that point. Instead of immediately closing the connection, the client can keep that connection unavailable to other callers while it tries to consume and discard the outstanding RESP reply. If that cleanup succeeds, the connection can be reused; otherwise it should still be closed.

Possible Implementation

For commands that were successfully written, read the response using an internal timeout after the caller context expires. Mark the connection reusable only if the read/drain completes successfully.

I have a prototype and can open a PR if this direction is acceptable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions