Repository navigation
fix(connection): convert sync Retry to async Retry in sync_to_async_redis - #817
Merged
Merged
Conversation
…edis A sync redis.retry.Retry passed the kwargs filter unchanged, and the async connection awaits retry.call_with_retry, so the sync one returned the coroutine unawaited and the policy never ran: a converted client failed on the first command after CLIENT KILL where a native async client recovers. _async_connection_kwargs now rebuilds a sync Retry as redis.asyncio.retry.Retry with the same backoff object, retry count and supported error set. retry=None and a missing keyword are left alone. Unit tests pin the conversion on redis-py 6.3.0, 7.4.1, 8.0.1 and 8.1.0; an integration test kills the converted client's connection and checks the next command succeeds (it fails without the fix on redis-py 8.1.0).
vishal-bala
self-requested a review
November 5, 2026 09:40
vishal-bala
requested changes
Nov 5, 2026
vishal-bala
left a comment
Collaborator
There was a problem hiding this comment.
Thanks for picking this up from the #792 thread! The fix looks right; I checked it on redis-py 6.3 through 8.1. A few small test tweaks and one docstring correction, and then we should be good to go.
Use a non-default retry count so a converter that ignored the caller's count would fail, drop two assertions the remaining test already covers, and correct the integration test's docstring: the immediate ping after CLIENT KILL fails on main on redis-py 6.3 as well as 8.1, so the test exercises the policy on every supported version.
Contributor
Author
|
Thanks. Pushed
|
vishal-bala
self-requested a review
November 5, 2026 13:14
vishal-bala
approved these changes
Nov 6, 2026
|
🚀 PR was released in |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #792, from this review comment.
Motivation
sync_to_async_redispassed the sync client'sretrykeyword through unchanged. The async connection awaitsretry.call_with_retry(...), and a syncredis.retry.Retryreturns the coroutine without awaiting it, so the retry policy never ran: a converted client failed on the first command afterCLIENT KILL, where a native async client recovers.Changes
_async_connection_kwargsrebuilds a syncRetryasredis.asyncio.retry.Retrywith the same backoff object, retry count and supported error set (_async_retry).retry=Noneand a missing keyword are left alone.tests/unit/test_sync_to_async_redis.pypin the conversion; an integration test intests/integration/test_connection.pykills the converted client's connection and checks the next command succeeds.Release Notes
Async paths that convert a caller's sync client (
SemanticCache,AsyncSearchIndex, and so on) now keep that client's retry policy, so they reconnect after a dropped connection the way a native async client does.Reviewer Brief
Start here:
redisvl/redis/connection.py,_async_retry. A client converted from sync to async keeps its retry policy only if this rebuilds it, and_async_connection_kwargscalls it for every conversion, including a plainRedis(), which carries aRetryby default.Where it could fail
redisvl/redis/connection.py:383:_async_retryreadsRetry._backoffandRetry._supported_errors, private attributes with no public getter in redis-py 6.3 through 8.1; if a future release renames one, every conversion raisesAttributeErrorinstead of quietly dropping the policy.redisvl/redis/connection.py:421: a user'sRetrysubclass is rebuilt as the stock asyncRetry, so an overriddencall_with_retryis not carried over (it could not have run on the async connection before this change either).Not verified: cluster and Sentinel clients (both are rejected before this code runs); redis-py versions between 6.3.0 and 8.1.0 other than 7.4.1 and 8.0.1.
Beyond CI:
test_converted_client_recovers_after_client_killfailed 20 of 20 runs onmainand passed 20 of 20 with this change, on both redis-py 6.3.0 and 8.1.0. The unit tests pass on redis-py 6.3.0, 7.4.1, 8.0.1 and 8.1.0, and hardcoding the retry count in_async_retrymakestest_sync_retry_is_rebuilt_as_the_async_retryfail. A sync client built withretry_on_timeout=Trueorretry_on_error=[BusyLoadingError]converts to an async connection whoseRetryincludes those errors, on 6.3.0 and 8.1.0.Since the last brief:
57e898etightens the tests only: a non-default retry count of 5, two redundant tests and assertions dropped, and a clearer CLIENT KILL test docstring.Reviewed
57e898e· Claude Code (claude-opus-5-5) · lenses: correctness, security, design, tests, docs, Redis behaviourNote
Medium Risk
Reliability fix on the sync-to-async path used by async cache/index flows; conversion relies on redis-py private
Retryfields that could break on a future redis-py release.Overview
sync_to_async_redisno longer forwards the sync client’sRetryunchanged. It now rebuilds it asredis.asyncio.retry.Retryvia_async_retry, preserving backoff, retry count, and supported errors so reconnect-and-retry actually runs on async connections (syncRetrywould leave coroutines unawaited and skip the policy)._async_connection_kwargsapplies that conversion whenretryis a syncRetry;retry=Noneor a missing keyword is unchanged. Docs forsync_to_async_redisnote the behavior.Unit tests assert the async
Retrymatches the sync policy; an integration test **CLIENT KILL**s a converted client and expects the nextpingto succeed.Reviewed by Cursor Bugbot for commit 57e898e. Bugbot is set up for automated code reviews on this repo. Configure here.