Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
### Option 1: Manual Setup

```sh
docker run --net=host --rm -v ./redis:/usr/local/etc/redis --name test-redis redis redis-server /usr/local/etc/redis/redis.conf
docker run --rm -p 6379:6379 -v ./redis:/usr/local/etc/redis --name test-redis redis redis-server /usr/local/etc/redis/redis.conf

pixi run serve
```
Expand Down Expand Up @@ -48,7 +48,7 @@ for i in {1..20}; do curl -s -D - http://localhost:8000/stream/live 2>/dev/null
Before running tests, start Redis:

```sh
docker run --net=host --rm -v ./redis:/usr/local/etc/redis --name test-redis redis redis-server /usr/local/etc/redis/redis.conf
docker run --rm -p 6379:6379 -v ./redis:/usr/local/etc/redis --name test-redis redis redis-server /usr/local/etc/redis/redis.conf
```

### Run the Test Suite
Expand Down
9 changes: 8 additions & 1 deletion server.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@
class Settings(BaseSettings):
redis_url: str = "redis://localhost:6379/0"
ttl: int = 60 * 60 # 1 hour
socket_timeout: float = 10.0 # 5 seconds
socket_connect_timeout: float = 10.0 # 10 seconds


def build_app(settings: Settings):
redis_client = redis.from_url(settings.redis_url)
# This doesn't connect to the redis, so it will work if redis is down.
redis_client = redis.from_url(
settings.redis_url,
socket_timeout=settings.socket_timeout,
socket_connect_timeout=settings.socket_connect_timeout,
)

@asynccontextmanager
async def lifespan(app: FastAPI):
Expand Down
51 changes: 51 additions & 0 deletions tests/test_redis_timeout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import time
import pytest
import redis.asyncio as redis


def test_redis_command_with_slow_operation():
"""Test that Redis operations timeout when they take too long."""
import asyncio
from server import Settings

# Create Redis client with timeout configuration
redis_client = redis.from_url(
"redis://localhost:6379/0",
# Operations will hang indefinitely without this timeout.
socket_timeout=1.0, # 1 second timeout
retry_on_timeout=False
)

async def run_slow_operation():
# Use a Lua script that busy-waits for 3 seconds (longer than timeout)
slow_script = """
local start_time = tonumber(redis.call('TIME')[1])
local end_time = start_time + 3

while tonumber(redis.call('TIME')[1]) < end_time do
-- busy wait
end

return "done"
"""

# This should timeout because the script takes 3 seconds but timeout is 1s
result = await redis_client.eval(slow_script, 0)
return result

start_time = time.time()

# This should timeout, not complete successfully
with pytest.raises((redis.TimeoutError)):
asyncio.run(run_slow_operation())

elapsed_time = time.time() - start_time

# Should timeout within a reasonable time (much less than 3 seconds)
assert elapsed_time < 2.0, f"Redis operation took too long: {elapsed_time} seconds"

# Clean up
try:
asyncio.run(redis_client.aclose())
except Exception:
pass