strat-gameplay-webapp/backend/app/services/redis_client.py
Cal Corum a4b99ee53e CLAUDE: Replace black and flake8 with ruff for formatting and linting
Migrated to ruff for faster, modern code formatting and linting:

Configuration changes:
- pyproject.toml: Added ruff 0.8.6, removed black/flake8
- Configured ruff with black-compatible formatting (88 chars)
- Enabled comprehensive linting rules (pycodestyle, pyflakes, isort,
  pyupgrade, bugbear, comprehensions, simplify, return)
- Updated CLAUDE.md: Changed code quality commands to use ruff

Code improvements (490 auto-fixes):
- Modernized type hints: List[T] → list[T], Dict[K,V] → dict[K,V],
  Optional[T] → T | None
- Sorted all imports (isort integration)
- Removed unused imports
- Fixed whitespace issues
- Reformatted 38 files for consistency

Bug fixes:
- app/core/play_resolver.py: Fixed type hint bug (any → Any)
- tests/unit/core/test_runner_advancement.py: Removed obsolete random mock

Testing:
- All 739 unit tests passing (100%)
- No regressions introduced

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 15:33:21 -06:00

114 lines
2.8 KiB
Python

"""
Redis connection client for caching.
Provides async Redis client with connection pooling for
position ratings and other cached data.
Author: Claude
Date: 2025-11-03
Phase: 3E-Final
"""
import logging
import redis.asyncio as redis
from redis.asyncio import Redis
from redis.exceptions import RedisError
logger = logging.getLogger(f"{__name__}.RedisClient")
class RedisClient:
"""
Async Redis client with connection pooling.
Singleton pattern - use redis_client instance.
"""
def __init__(self):
self._redis: Redis | None = None
self._url: str | None = None
async def connect(self, redis_url: str = "redis://localhost:6379/0") -> None:
"""
Connect to Redis server.
Args:
redis_url: Redis connection URL
Format: redis://host:port/db
Example: redis://localhost:6379/0
"""
if self._redis is not None:
logger.warning("Redis client already connected")
return
try:
self._url = redis_url
self._redis = await redis.from_url(
redis_url,
encoding="utf-8",
decode_responses=True,
max_connections=10, # Connection pool size
)
# Test connection
await self._redis.ping()
logger.info(f"Redis connected successfully: {redis_url}")
except RedisError as e:
logger.error(f"Failed to connect to Redis at {redis_url}: {e}")
self._redis = None
raise
async def disconnect(self) -> None:
"""Disconnect from Redis server."""
if self._redis is not None:
await self._redis.close()
await self._redis.connection_pool.disconnect()
self._redis = None
logger.info("Redis disconnected")
@property
def client(self) -> Redis:
"""
Get Redis client instance.
Returns:
Redis client
Raises:
RuntimeError: If not connected
"""
if self._redis is None:
raise RuntimeError(
"Redis client not connected. "
"Call await redis_client.connect() first."
)
return self._redis
@property
def is_connected(self) -> bool:
"""Check if Redis is connected."""
return self._redis is not None
async def ping(self) -> bool:
"""
Test Redis connection.
Returns:
True if Redis is responding, False otherwise
"""
if not self.is_connected:
return False
try:
await self._redis.ping()
return True
except RedisError as e:
logger.error(f"Redis ping failed: {e}")
return False
# Singleton instance
redis_client = RedisClient()