Skip to content

RecursionError in redis.asyncio when using retry_on_timeout or health_check_interval #3745

@everpoint-saas

Description

@everpoint-saas

This might be related to #2893 (Sentinel recursion), but it also happens in non-Sentinel setups

Bug Description
redis.asyncio enters infinite recursion when retry_on_timeout=True or health_check_interval>0 are set.

Environment

Python: 3.11.x, 3.12.x (both affected)

redis-py: 5.0.1 (also tested with 4.6.0)

Parser: default (no hiredis)

OS: Docker (python:3.12-slim-bookworm)

uvloop: disabled

Minimal Reproduction

import asyncio
import redis.asyncio as redis

async def reproduce():
client = redis.from_url(
"redis://default:password@localhost:6379/0",
retry_on_timeout=True,
health_check_interval=30,
)
await client.ping() # RecursionError

asyncio.run(reproduce())

Working Configuration

client = redis.from_url(
"redis://default:password@localhost:6379/0",
retry_on_timeout=False,
health_check_interval=0,
)

Stack Trace Pattern
RecursionError: maximum recursion depth exceeded

connect() → on_connect() → send_command("CLIENT SETINFO")

→ check_health() → _send_ping() → send_command("PING")

→ back to connect() (infinite loop)

Key Findings

Trigger: enabling retry or health check during initial connection.

Not Python-version-specific, reproducible on 3.11 and 3.12.

Not parser-specific (occurs with PythonParser too).

Root cause: circular dependency between connection setup and health check.

Workaround
Disable retry and health check:

redis.from_url(..., retry_on_timeout=False, health_check_interval=0)

Expected Behavior
Health checks and retries should not trigger recursion during connection initialization.

Metadata

Metadata

Assignees

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