Archived
refactor: aria2 改手写原生异步 JSON-RPC,aria2p 与同步 HTTP 栈从依赖树清零
为什么:aria2p 内部是 requests + websocket-client 的同步实现,每个 RPC 都是一次 「同步网络 IO 藏在 to_thread 里」——线程池跑得再满也不产生真正的并发,每次轮询 还要额外付一次线程跳转。这是本项目最后一处此类残留,删掉后整个进程的网络 IO 都走同一个 aiohttp 连接池。 改动: - music_downloader/_aria2.py 整体重写:新增 _Aria2Rpc,直接向 aria2 的 JSON-RPC 2.0 端点发 getVersion / addUri / tellStatus / forceRemove / removeDownloadResult,一律走 core.http_client.request_once(不重试,与 aria2p 口径一致);新增 Aria2RpcError 承载 HTTP 200 + error 对象的协议错误。 - _abort 逐条复刻 aria2p.remove(force=True, files=?, clean=True) 语义:终态走 removeDownloadResult;在途先 forceRemove 再清结果表;控制文件 .aria2 无条件 删除(clean=True 默认);仅当 files 且主移除成功才删数据文件。 - get_backend / _try_start 改原生异步:asyncio.Lock 单飞 + await rpc.get_version() 探活,不再用 to_thread 包 subprocess.Popen;超时路径改 to_thread(_reap) 回收。 - 新增 Protocol _Rpc / _ProcessHandle(补 returncode 声明)——只声明本模块真正 调用的方法,测试据此用轻量替身驱动状态机,不必依赖真实 aria2 进程。 - pyproject.toml 删 aria2p 依赖并同步更新过时注释;uv lock 连带移除 8 个传递 依赖:requests / urllib3 / websocket-client / charset-normalizer / loguru / platformdirs / win32-setctime。至此全仓无任何 requests 栈。 - tests/test_aria2.py 重写为 21 项用例(_FakeRpc / _FakeProc / _LiveProc / _FakeHTTP 替身),新增终态体积守卫、_try_start 三分支(就绪重试 / 超时不就绪 杀进程 / 进程提前退出)与 JSON-RPC 信封四例。 - tests/test_downloader.py 的 get_backend 替身由同步 lambda 改为协程——调用点 已直接 await,同步替身会被 await 成 None 而报 TypeError。 验证(在 aria2p 已物理移除的环境上复核,故能真正证明无残留依赖): - uv run ruff check . → All checks passed! - uv run pyright → 0 errors, 0 warnings, 0 informations - uv run pytest → 392 项,0 失败 / 0 error / 0 skipped(基线 382,净增 10) - data/site.db sha256 前后一致(a19f5dbf…6487),无 -wal/-shm 残留
This commit is contained in:
1 parent
6c7f8f589e
commit
046225e38d
6 files changed
+516
-338
No files matched your search
+5
-3
@@ -15,7 +15,6 @@ dependencies = [
|
||||
"qrcode>=7.0,<8.3",
|
||||
"python-multipart>=0.0.9",
|
||||
"filetype>=1.2.0",
|
||||
"aria2p>=0.12.1",
|
||||
"mutagen>=1.48.1",
|
||||
]
|
||||
|
||||
@@ -67,11 +66,14 @@ ignore = [
|
||||
# 不是「用 sleep 当超时」的反模式。
|
||||
"core/http_client.py" = ["ASYNC109"]
|
||||
# ASYNC109:timeout 是**总下载时限**(交给 aria2 轮询循环判定),不是「用 sleep 当超时」。
|
||||
"music_downloader/_aria2.py" = ["ASYNC109"]
|
||||
# ASYNC240:搬迁后才出现的阻塞文件操作只有 unlink(删残片/控制文件)——目录项删除,
|
||||
# 微秒级且不碰网络,卸载到线程的调度开销大于操作本身,与 downloader.py 同口径。
|
||||
"music_downloader/_aria2.py" = ["ASYNC109", "ASYNC240"]
|
||||
# ASYNC230/240:残留的阻塞文件系统调用都是**本地元数据/短写**——exists()/stat()/
|
||||
# os.replace()/往 .part 顺序写分块,微秒级且不碰网络,卸载到线程的调度开销大于操作
|
||||
# 本身。真正的重活(mutagen 全量重写标签、zipfile 整段拷贝、shutil.rmtree、同步
|
||||
# SQLite 落库、aria2p 的同步 RPC)都已各自 to_thread 卸载。
|
||||
# SQLite 落库)都已各自 to_thread 卸载;aria2 的 RPC 已改为手写原生异步实现
|
||||
# (music_downloader/_aria2.py),不再是阻塞调用。
|
||||
"music_downloader/downloader.py" = ["ASYNC230", "ASYNC240"]
|
||||
"services/podcast.py" = ["ASYNC230", "ASYNC240"]
|
||||
"services/batch.py" = ["ASYNC240"]
|
||||
|
||||
Reference in new issue
Block a user