Skip to content

fix: preserve Redis client ownership boundaries - #705

Open
mikemikimike wants to merge 1 commit into
redis:mainfrom
mikemikimike:fix/client-ownership-660
Open

fix: preserve Redis client ownership boundaries#705
mikemikimike wants to merge 1 commit into
redis:mainfrom
mikemikimike:fix/client-ownership-660

Conversation

@mikemikimike

@mikemikimike mikemikimike commented Aug 29, 2026

Copy link
Copy Markdown

Summary

Fixes #660.

SearchIndex.set_client() could keep ownership of a caller-provided Redis client and close it during disconnect or garbage collection. It also left the previously owned client open when replacing it. The sync connect() path had the corresponding replacement-lifecycle gap.

This change closes a previously owned client before replacement, marks clients supplied through set_client() as unowned, and keeps clients created by connect() owned by the index. Async ownership behavior is preserved and covered by a focused regression test.

Compatibility

Explicitly injected clients are no longer closed by the index, matching constructor injection semantics. Clients created by connect() remain index-owned and are closed as before. No Redis protocol or data behavior changes.

Validation

  • .venv\\Scripts\\python.exe -m pytest tests/unit/test_connection_normalization.py -q --confcutdir=tests/unit -p pytest_asyncio — 12 passed.
  • .venv\\Scripts\\python.exe -m pytest tests/unit/test_index_gc_finalizer.py -q --confcutdir=tests/unit -p pytest_asyncio — 11 passed.
  • python -m ruff check redisvl/index/index.py tests/unit/test_connection_normalization.py tests/unit/test_index_gc_finalizer.py — passed.
  • python -m ruff format --check redisvl/index/index.py tests/unit/test_connection_normalization.py — passed.
  • git diff --check — passed.

The repository Docker-based test fixture was attempted, but pulling redis:8.4 failed with a registry EOF before any service started. The changed paths are covered by service-free unit tests; full Docker-backed integration tests were not run.


Note

Medium Risk
Changes connection teardown semantics for apps using deprecated connect()/set_client(); injected clients will no longer be closed by the index, which fixes a bug but may leave connections open if callers relied on the old behavior.

Overview
Fixes incorrect Redis client lifecycle on sync SearchIndex when swapping connections: set_client() no longer treats caller-supplied clients as index-owned, and connect() now closes and detaches a previously index-owned client before opening a new factory connection.

SearchIndex.connect() — If the index currently owns its client, the change detaches the GC finalizer, closes that client, then builds a new connection and sets _owns_redis_client = True so disconnect() still closes factory-created clients.

SearchIndex.set_client() — Same cleanup when replacing an owned client, then sets _owns_redis_client = False so injected clients are never closed by disconnect() or ownership finalizers (aligned with constructor redis_client= behavior).

Unit tests in test_connection_normalization.py lock in: owned client closed on set_client, external client left open on disconnect; connect() closes the old owned client and keeps ownership of the new one; async set_client does not take ownership.

Reviewed by Cursor Bugbot for commit 9dc39ae. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 9dc39ae. Configure here.

Comment thread redisvl/index/index.py
if self._owns_redis_client:
self._detach_client_finalizer()
if self.__redis_client is not None:
self.__redis_client.close()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failed connect closes the live client

Medium Severity

A failed connect() closes the currently owned Redis client before the replacement is created, so a ConnectionError or missing REDIS_URL leaves the index pointing at a closed client. Later operations keep using that dead connection instead of recovering.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9dc39ae. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

set_client() keeps client ownership, so the index closes a caller-provided client

1 participant