fix:修复音频代理缓存报错
This commit is contained in:
@@ -39,6 +39,9 @@ engine = create_async_engine(
|
|||||||
# Redis 连接
|
# Redis 连接
|
||||||
redis_client = redis.from_url(settings.redis_url, decode_responses=True)
|
redis_client = redis.from_url(settings.redis_url, decode_responses=True)
|
||||||
|
|
||||||
|
# Redis 二进制数据连接 (不自动解码响应,用于存储音频等二进制数据)
|
||||||
|
redis_binary_client = redis.from_url(settings.redis_url, decode_responses=False)
|
||||||
|
|
||||||
# Redis 消息缓存连接 (db1) - 使用同步客户端在线程池中执行
|
# Redis 消息缓存连接 (db1) - 使用同步客户端在线程池中执行
|
||||||
redis_message_client = sync_redis.from_url(settings.redis_url, decode_responses=True, db=1)
|
redis_message_client = sync_redis.from_url(settings.redis_url, decode_responses=True, db=1)
|
||||||
|
|
||||||
@@ -82,6 +85,11 @@ def get_redis():
|
|||||||
return redis_client
|
return redis_client
|
||||||
|
|
||||||
|
|
||||||
|
def get_redis_binary():
|
||||||
|
"""获取二进制数据专用的 Redis 客户端 (不自动解码响应)"""
|
||||||
|
return redis_binary_client
|
||||||
|
|
||||||
|
|
||||||
def get_redis_message():
|
def get_redis_message():
|
||||||
"""获取消息专用的 Redis 客户端 (db1)"""
|
"""获取消息专用的 Redis 客户端 (db1)"""
|
||||||
return redis_message_client
|
return redis_message_client
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
|
|
||||||
from app.dependencies.database import get_redis
|
from app.dependencies.database import get_redis, get_redis_binary
|
||||||
from app.service.audio_proxy_service import AudioProxyService, get_audio_proxy_service
|
from app.service.audio_proxy_service import AudioProxyService, get_audio_proxy_service
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Path
|
from fastapi import APIRouter, Depends, HTTPException, Path
|
||||||
@@ -18,9 +18,12 @@ import redis.asyncio as redis
|
|||||||
router = APIRouter(prefix="/audio", tags=["Audio Proxy"])
|
router = APIRouter(prefix="/audio", tags=["Audio Proxy"])
|
||||||
|
|
||||||
|
|
||||||
async def get_audio_proxy_dependency(redis_client: Annotated[redis.Redis, Depends(get_redis)]) -> AudioProxyService:
|
async def get_audio_proxy_dependency(
|
||||||
|
redis_binary_client: Annotated[redis.Redis, Depends(get_redis_binary)],
|
||||||
|
redis_text_client: Annotated[redis.Redis, Depends(get_redis)],
|
||||||
|
) -> AudioProxyService:
|
||||||
"""音频代理服务依赖注入"""
|
"""音频代理服务依赖注入"""
|
||||||
return get_audio_proxy_service(redis_client)
|
return get_audio_proxy_service(redis_binary_client, redis_text_client)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/beatmapset/{beatmapset_id}")
|
@router.get("/beatmapset/{beatmapset_id}")
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ import redis.asyncio as redis
|
|||||||
class AudioProxyService:
|
class AudioProxyService:
|
||||||
"""音频代理服务"""
|
"""音频代理服务"""
|
||||||
|
|
||||||
def __init__(self, redis_client: redis.Redis):
|
def __init__(self, redis_binary_client: redis.Redis, redis_text_client: redis.Redis):
|
||||||
self.redis = redis_client
|
self.redis_binary = redis_binary_client
|
||||||
|
self.redis_text = redis_text_client
|
||||||
self.http_client = httpx.AsyncClient(timeout=30.0)
|
self.http_client = httpx.AsyncClient(timeout=30.0)
|
||||||
self._cache_ttl = 7 * 24 * 60 * 60 # 7天缓存
|
self._cache_ttl = 7 * 24 * 60 * 60
|
||||||
|
|
||||||
async def close(self):
|
async def close(self):
|
||||||
"""关闭HTTP客户端"""
|
"""关闭HTTP客户端"""
|
||||||
@@ -37,14 +38,14 @@ class AudioProxyService:
|
|||||||
cache_key = self._get_beatmapset_cache_key(beatmapset_id)
|
cache_key = self._get_beatmapset_cache_key(beatmapset_id)
|
||||||
metadata_key = self._get_beatmapset_metadata_key(beatmapset_id)
|
metadata_key = self._get_beatmapset_metadata_key(beatmapset_id)
|
||||||
|
|
||||||
# 获取音频数据和元数据
|
# 获取音频数据(二进制)和元数据(文本)
|
||||||
audio_data = await self.redis.get(cache_key)
|
audio_data = await self.redis_binary.get(cache_key)
|
||||||
metadata = await self.redis.get(metadata_key)
|
metadata = await self.redis_text.get(metadata_key)
|
||||||
|
|
||||||
if audio_data and metadata:
|
if audio_data and metadata:
|
||||||
logger.debug(f"Beatmapset audio cache hit for ID: {beatmapset_id}")
|
logger.debug(f"Beatmapset audio cache hit for ID: {beatmapset_id}")
|
||||||
# metadata 格式为 "content_type"
|
# audio_data 已经是 bytes 类型,metadata 是 str 类型
|
||||||
return audio_data, metadata.decode()
|
return audio_data, metadata
|
||||||
return None
|
return None
|
||||||
except (redis.RedisError, redis.ConnectionError) as e:
|
except (redis.RedisError, redis.ConnectionError) as e:
|
||||||
logger.error(f"Error getting beatmapset audio from cache: {e}")
|
logger.error(f"Error getting beatmapset audio from cache: {e}")
|
||||||
@@ -56,9 +57,9 @@ class AudioProxyService:
|
|||||||
cache_key = self._get_beatmapset_cache_key(beatmapset_id)
|
cache_key = self._get_beatmapset_cache_key(beatmapset_id)
|
||||||
metadata_key = self._get_beatmapset_metadata_key(beatmapset_id)
|
metadata_key = self._get_beatmapset_metadata_key(beatmapset_id)
|
||||||
|
|
||||||
# 缓存音频数据和元数据
|
# 缓存音频数据(二进制)和元数据(文本)
|
||||||
await self.redis.setex(cache_key, self._cache_ttl, audio_data)
|
await self.redis_binary.setex(cache_key, self._cache_ttl, audio_data)
|
||||||
await self.redis.setex(metadata_key, self._cache_ttl, content_type)
|
await self.redis_text.setex(metadata_key, self._cache_ttl, content_type)
|
||||||
|
|
||||||
logger.debug(f"Cached beatmapset audio for ID: {beatmapset_id}, size: {len(audio_data)} bytes")
|
logger.debug(f"Cached beatmapset audio for ID: {beatmapset_id}, size: {len(audio_data)} bytes")
|
||||||
except (redis.RedisError, redis.ConnectionError) as e:
|
except (redis.RedisError, redis.ConnectionError) as e:
|
||||||
@@ -122,7 +123,7 @@ class AudioProxyService:
|
|||||||
return audio_data, content_type
|
return audio_data, content_type
|
||||||
|
|
||||||
|
|
||||||
def get_audio_proxy_service(redis_client: redis.Redis) -> AudioProxyService:
|
def get_audio_proxy_service(redis_binary_client: redis.Redis, redis_text_client: redis.Redis) -> AudioProxyService:
|
||||||
"""获取音频代理服务实例"""
|
"""获取音频代理服务实例"""
|
||||||
# 每次创建新实例,避免全局状态
|
# 每次创建新实例,避免全局状态
|
||||||
return AudioProxyService(redis_client)
|
return AudioProxyService(redis_binary_client, redis_text_client)
|
||||||
|
|||||||
Reference in New Issue
Block a user