Archived
chore(async-infra): 异步基础层 + 工具链 + 清理
异步基础层(core/):
- db.py aiosqlite + WAL:读路径无锁并发、写路径 asyncio.Lock 串行,
busy_timeout 自旋——实现「读写同时进行」(旧实现用 RLock 全读串行)
- http_client.py aiohttp 连接池 + 有界重试(5xx 重试 / 4xx 不重试)+
响应体上限 + 流式接口;按事件循环隔离 session(支持迁移期双 loop)
工具链:
- pyproject.toml ruff(E/F/W/I/B/UP/C4/ASYNC/S/RUF) + pyright(basic) + pytest(asyncio auto)
- requirements-fastapi.txt FastAPI/aiohttp/aiosqlite/aiofiles 等目标栈
- requirements-dev.txt 开发依赖(pytest/ruff/pyright)
清理:删除无用脚本 _csscheck.py 与产物标记 _css_ok.txt/_pkg_ok.txt,同步 .gitignore
验证:pytest 10/10(含「写 200 条同时 4 读协程零异常」并发用例);
ruff All checks passed;pyright 0 errors。
This commit is contained in:
1 parent
41356e89c4
commit
9f56f68b66
16 files changed
+706
-42
No files matched your search
@@ -12,6 +12,7 @@
|
||||
两套独立进程语义。生产切换前需按计划把状态与任务模型统一(见迁移计划阶段 C),
|
||||
当前仅用于开发期联调。
|
||||
"""
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
from core.config import APP_VERSION
|
||||
@@ -40,5 +41,7 @@ def create_app(serve_flask_fallback: bool = False) -> FastAPI:
|
||||
def _mount_flask_fallback(app: FastAPI) -> None:
|
||||
"""把遗留 Flask WSGI 应用挂到根路径,兜底未迁移的路由。"""
|
||||
from starlette.middleware.wsgi import WSGIMiddleware
|
||||
|
||||
import main as legacy_flask
|
||||
|
||||
app.mount('/', WSGIMiddleware(legacy_flask.app))
|
||||
@@ -4,6 +4,7 @@
|
||||
开发期启动: .venv/Scripts/python.exe web/main.py
|
||||
生产切换前需先将状态/任务模型与既有 Flask 进程统一(见迁移计划阶段 C)。
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ FastAPI 侧改为直接返回 JSONResponse,但**包体结构完全一致**:
|
||||
error: {"status": sc, "success": false, "message": msg, ["error_code": ...]}
|
||||
这样前端无需任何改动即可同时对接两个框架。
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from fastapi.responses import JSONResponse
|
||||
@@ -24,7 +25,7 @@ def success(data: Any = None, message: str = 'success', status_code: int = 200)
|
||||
return JSONResponse(content=body, status_code=status_code)
|
||||
|
||||
|
||||
def error(message: str, status_code: int = 400, error_code: str = None) -> JSONResponse:
|
||||
def error(message: str, status_code: int = 400, error_code: str | None = None) -> JSONResponse:
|
||||
"""错误响应(对应 Flask APIResponse.error)"""
|
||||
body = {
|
||||
'status': status_code,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
此处实现与 main.py 的 health_check / api_info **响应契约逐字段对齐**,
|
||||
用于验证双框架一致性(见 .zcode/refactor/parity.py)。
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
@@ -41,6 +42,7 @@ def health_check():
|
||||
"""健康检查API(对应 Flask health_check)"""
|
||||
try:
|
||||
from music_api import load_cookies
|
||||
|
||||
cookies = load_cookies()
|
||||
cookie_status = 'valid' if cookies else 'invalid'
|
||||
|
||||
@@ -49,7 +51,7 @@ def health_check():
|
||||
'timestamp': int(time.time()) if 'time' in sys.modules else None,
|
||||
'cookie_status': cookie_status,
|
||||
'cookie_count': len(cookies),
|
||||
'downloads_dir': 'configured', # R5-P3:不向匿名访客回显服务器绝对路径
|
||||
'downloads_dir': 'configured', # R5-P3:不向匿名访客回显服务器绝对路径
|
||||
'version': APP_VERSION,
|
||||
}
|
||||
return success(health_info, "API服务运行正常")
|
||||
@@ -66,10 +68,7 @@ def api_info():
|
||||
'version': APP_VERSION,
|
||||
'description': '云村小助手 · 网易云音乐解析/下载服务',
|
||||
'endpoints': dict(_ENDPOINTS),
|
||||
'supported_qualities': [
|
||||
'standard', 'exhigh', 'lossless',
|
||||
'hires', 'sky', 'jyeffect', 'jymaster', 'dolby'
|
||||
],
|
||||
'supported_qualities': ['standard', 'exhigh', 'lossless', 'hires', 'sky', 'jyeffect', 'jymaster', 'dolby'],
|
||||
'config': {
|
||||
'downloads_dir': 'configured',
|
||||
'max_body_bytes': '2MB(备份上传 200MB)',
|
||||
|
||||
Reference in new issue
Block a user