diff --git a/.env.example b/.env.example index f1a89a1..94875da 100644 --- a/.env.example +++ b/.env.example @@ -6,7 +6,7 @@ MYSQL_DATABASE="osu_api" MYSQL_USER="osu_api" MYSQL_PASSWORD="password" MYSQL_ROOT_PASSWORD="password" -REDIS_URL="redis://127.0.0.1:6379/0" +REDIS_URL="redis://127.0.0.1:6379" # JWT Settings # Use `openssl rand -hex 32` to generate a secure key diff --git a/app/config.py b/app/config.py index 53949aa..e2650b0 100644 --- a/app/config.py +++ b/app/config.py @@ -141,7 +141,7 @@ STORAGE_SETTINGS='{ ] redis_url: Annotated[ str, - Field(default="redis://127.0.0.1:6379/0", description="Redis 连接 URL"), + Field(default="redis://127.0.0.1:6379", description="Redis 连接 URL"), "数据库设置", ] diff --git a/app/dependencies/database.py b/app/dependencies/database.py index 3d490f2..a058725 100644 --- a/app/dependencies/database.py +++ b/app/dependencies/database.py @@ -35,13 +35,16 @@ engine = create_async_engine( ) # Redis 连接 -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_client = redis.from_url(settings.redis_url, decode_responses=True, db=0) # Redis 消息缓存连接 (db1) -redis_message_client: redis.Redis = redis.from_url(settings.redis_url, decode_responses=True, db=1) +redis_message_client = redis.from_url(settings.redis_url, decode_responses=True, db=1) + +# Redis 二进制数据连接 (不自动解码响应,用于存储音频等二进制数据,db2) +redis_binary_client = redis.from_url(settings.redis_url, decode_responses=False, db=2) + +# Redis 限流连接 (db3) +redis_rate_limit_client = redis.from_url(settings.redis_url, decode_responses=True, db=3) # 数据库依赖 diff --git a/app/router/notification/server.py b/app/router/notification/server.py index 021a690..7818887 100644 --- a/app/router/notification/server.py +++ b/app/router/notification/server.py @@ -8,7 +8,7 @@ from app.dependencies.database import ( DBFactory, Redis, get_db_factory, - get_redis, + redis_message_client, with_db, ) from app.dependencies.user import get_current_user_and_token @@ -31,7 +31,7 @@ class ChatServer: def __init__(self): self.connect_client: dict[int, WebSocket] = {} self.channels: dict[int, list[int]] = {} - self.redis: Redis = get_redis() + self.redis: Redis = redis_message_client self.tasks: set[asyncio.Task] = set() self.ChatSubscriber = ChatSubscriber() diff --git a/docker-compose-osurx.yml b/docker-compose-osurx.yml index 9cd1c92..b06bad1 100644 --- a/docker-compose-osurx.yml +++ b/docker-compose-osurx.yml @@ -11,7 +11,7 @@ services: environment: - MYSQL_HOST=mysql - MYSQL_PORT=3306 - - REDIS_URL=redis://redis:6379/0 + - REDIS_URL=redis://redis:6379 - ENABLE_OSU_RX=true - ENABLE_OSU_AP=true - ENABLE_ALL_MODS_PP=true diff --git a/docker-compose.yml b/docker-compose.yml index 1a82af3..a2a769f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: environment: - MYSQL_HOST=mysql - MYSQL_PORT=3306 - - REDIS_URL=redis://redis:6379/0 + - REDIS_URL=redis://redis:6379 env_file: - .env depends_on: diff --git a/main.py b/main.py index 6646afb..a9ebed6 100644 --- a/main.py +++ b/main.py @@ -4,7 +4,14 @@ from pathlib import Path from app.config import settings from app.database import User -from app.dependencies.database import Database, engine, get_redis, redis_client +from app.dependencies.database import ( + Database, + engine, + redis_binary_client, + redis_client, + redis_message_client, + redis_rate_limit_client, +) from app.dependencies.fetcher import get_fetcher from app.dependencies.scheduler import start_scheduler, stop_scheduler from app.log import system_logger @@ -50,39 +57,55 @@ import sentry_sdk @asynccontextmanager async def lifespan(app: FastAPI): # noqa: ARG001 - # on startup + # === on startup === + # init mods and achievements init_mods() init_ranked_mods() - await FastAPILimiter.init(get_redis()) - fetcher = await get_fetcher() # 初始化 fetcher - await init_geoip() # 初始化 GeoIP 数据库 + load_achievements() + + # init rate limiter + await FastAPILimiter.init(redis_rate_limit_client) + + # init fetcher + fetcher = await get_fetcher() + # init GeoIP + await init_geoip() + + # init game server await create_rx_statistics() await calculate_user_rank(True) await daily_challenge_job() await process_daily_challenge_top() await create_banchobot() - await start_email_processor() # 启动邮件队列处理器 - await download_service.start_health_check() # 启动下载服务健康检查 - await start_cache_tasks() # 启动缓存调度器 + + # services + await start_email_processor() + await download_service.start_health_check() + await start_cache_tasks() init_beatmapset_update_service(fetcher) # 初始化谱面集更新服务 - redis_message_system.start() # 启动 Redis 消息系统 - load_achievements() + redis_message_system.start() start_scheduler() - # 显示资源代理状态 + # show the status of AssetProxy if settings.enable_asset_proxy: system_logger("AssetProxy").info(f"Asset Proxy enabled - Domain: {settings.custom_asset_domain}") - # on shutdown yield + + # === on shutdown === + # stop services bg_tasks.stop() - redis_message_system.stop() # 停止 Redis 消息系统 - await stop_cache_tasks() # 停止缓存调度器 + await stop_cache_tasks() stop_scheduler() - await download_service.stop_health_check() # 停止下载服务健康检查 - await stop_email_processor() # 停止邮件队列处理器 + await download_service.stop_health_check() + await stop_email_processor() + + # close database & redis await engine.dispose() await redis_client.aclose() + await redis_binary_client.aclose() + await redis_message_client.aclose() + await redis_rate_limit_client.aclose() desc = f"""osu! API 模拟服务器,支持 osu! API v1, v2 和 osu!lazer 的绝大部分功能。