- GET /inventory/media-servers: per-instance Promise.allSettled, per-instance
concurrency cap (2) and timeout (8s); failed/timed-out instances are unknown,
response carries partial=true (field not yet in contracts)
- S-7: POST /files/identify returns local matches plus remoteTaskId/remotePending
and enqueues identifyRemote; the worker runs the TMDB lookups and publishes SSE
identify.completed {taskId,status,items,truncated,excludedBySize,error};
?wait=true keeps the synchronous path, capped at 15s overall
- catalog.lookup / release.search honour the caller's abort signal
- scripts/dev-db-clean.ts: dry-run by default, --yes to drop leftover test
schemas and w32-/w33-/fe4-/qa- prefixed entities; refuses non localhost:55433
- runbook: dev DB cleanup
Co-Authored-By: Claude Opus 5.5 <[email protected]>
7.7 KiB
开发环境运行手册
前置
- Deno 2.9.7(锁定;
curl -fsSL https://deno.land/install.sh | sh -s v2.9.7)、Docker。不需要 Node.js / pnpm。 - 端口:web 5180、API 4380、PG 55433。本机 3000/5175/5176/55432 已被其他项目占用,不要改用。
首次启动
cp .env.example .env # 按需修改;server 与 db 脚本都读仓库根 .env
deno task db:up # 起 postgres:16-alpine(docker-compose.dev.yml,数据卷 umt-pg-data)
deno install # 按 deno.lock 装依赖到 node_modules(成员包软链到 node_modules/@umt/*)
deno task db:migrate # 执行 packages/db/migrations 下全部迁移
deno task dev # 同时起 server(4380)与 web(5180)
单独起:deno task dev:server(deno run --watch,默认 --role all,API + worker 同进程)、deno task dev:web。
验证
curl localhost:4380/api/v1/health
# 开发模式可用 .env 的 DEV_ADMIN_KEY 作 admin
curl -N -H "Authorization: Bearer umt-dev-admin-key" "localhost:4380/api/v1/events?after=0" # SSE 流(控制台用)
curl -H "Authorization: Bearer umt-dev-admin-key" "localhost:4380/api/v1/events?after=0&limit=50" # JSON 补读页(API Key 调用者用)
- OpenAPI:http://localhost:4380/api/openapi.json,文档页 http://localhost:4380/api/docs
- 控制台:http://localhost:5180,右上角钥匙按钮设置 API Key(存 localStorage
umt-api-key)
常用命令
| 命令 | 作用 |
|---|---|
deno task ci |
typecheck(tsc 7.0.2 + deno check)→ lint(biome)→ test(vitest)→ check:tokens → build,提交前必须全绿 |
deno task typecheck |
deno types 生成 types/deno.d.ts 后,逐个成员跑 tsc 7.0.2,再跑 deno check(Deno 内置 TS 6.0.3) |
deno task lint / deno task fmt |
biome 检查 / 自动修复(含 import 排序;相对 import 必须带扩展名) |
deno task test |
逐个成员跑 vitest(deno run -A npm:vitest run);单包:cd packages/<x> && deno task test |
deno task db:reset |
清空 public schema 并重新迁移(生产环境拒绝执行) |
deno task gen:types |
从已迁移的库反射生成 packages/db/src/types.ts |
deno task gen:tokens |
改了 app.css 后重新生成 token 登记表 |
deno task build |
web 构建到 apps/web/build/client + server 编译为单文件 dist/umt-server |
cd apps/server && deno task start |
以受限权限(net/env/sys/read)直接跑源码 |
依赖:npm 包版本只在根 deno.json 的 imports 里登记(web 的前端依赖仍在 apps/web/package.json)。改完跑 deno install 更新 deno.lock。有安装脚本的新依赖需要 deno approve-scripts 显式批准。
进程角色
umt-server --role api|worker|worker:agent|all(源码:deno run ... apps/server/src/main.ts --role ...)。
| 角色 | 引擎 worker | OutboxRelay / 模块后台循环 |
|---|---|---|
api |
不起(只入队/信号/取消) | 不跑 |
worker(io 组) |
除 runAgent/resolveDecision 外的全部任务,并发 WORKER_CONCURRENCY(缺省 4) |
跑 |
worker:agent |
只跑 runAgent/resolveDecision,并发 WORKER_AGENT_CONCURRENCY(缺省 2) |
不跑 |
all |
io 组 + agent 组两个池(开发缺省) | 跑 |
分组 worker 只认领自己的任务(@umt/tasks 按任务名过滤认领),Agent 长会话不占文件复制的槽,反之亦然。
worker 里有事件循环延迟探针:偏差超过 5s 打 worker 事件循环延迟超过阈值 warn,次数随心跳事件(loopLagWarnings)发出。
启动时 bootstrap() 装配 apps/server/src/modules/ 下的四个业务模块(见 apps/server/README.md),并连接任务引擎。数据库不可达时进程启动失败并退出。
acquisition-organize 的后台循环只做编排:qB 同步(含阈值暂停/恢复)一个定时器;另一个定时器按阈值入队 cleanupDownloadCache、
巡检补投 submitDownload/verifyAndImport、每 6h 入队 reconcileLibrary,重活都在任务里跑。
POST /download-cache/cleanup、POST /library/reconcile 同样只入队,返回 {taskId, runId}(202)。
HTTP 调用外部 IO 型能力(release.search 实时搜索、release.inspect 刷新详情、identity.resolve、catalog.lookup includeRemote)
限时 15s,站点并发 2、TMDB 并发 4,超时 502 / 排队满 429。
一次性子命令(容器入口用):--role migrate(迁移到最新,迁移文件已编进二进制;随后迁移任务引擎的 openworkflow schema)、--role preflight(启动自检:生产环境拒绝占位符密钥与 root、DB 可达、WEB_ROOT/index.html 存在)、--role probe(打本机 /api/v1/health,HEALTHCHECK 用)。
设置 WEB_ROOT 后 API 进程在同一端口托管 web 构建产物:存在的文件直接返回,其余非 /api 路径回退 index.html。
Docker 单容器部署
export SECRET_MASTER_KEY=$(openssl rand -hex 32) POSTGRES_PASSWORD=$(openssl rand -hex 16)
docker compose up -d --build # 服务:app(4380)+ postgres(数据卷 umt-pg-data)
curl localhost:4380/api/v1/health
- 镜像:
denoland/deno:2.9.7构建 web 与deno compile出二进制,运行时debian:trixie-slim+ gosu + postgresql-client + 静态 ffprobe,root 启动修/data属主后降权到 PUID(缺省 10001)。 - 入口
docker/entrypoint.sh:迁移 → 自检 → 同时起 api、worker、worker:agent 三个进程;任一退出则停掉其余并以非 0 退出,由restart: unless-stopped拉起。 - 二进制编译时固定权限:
--allow-net --allow-env --allow-sys --allow-read --allow-write --allow-run=ffprobe,sha256sum;镜像带静态 ffprobe;运行期写入落在DATA_DIR(容器内/data)。完整部署说明见 deploy.md。 - 构建版本号:
APP_VERSION=v0.1.0 docker compose build(写入 web 的version.json)。
测试数据库
需要 PG 的测试(db、tasks)默认连 DATABASE_URL 或 55433 开发库,不可达时跳过。tasks 包可用 TASKS_TEST_DATABASE_URL 指定独立库;每个测试文件使用带 pid+随机后缀的独立 schema,结束时删除,多份测试并发跑也不冲突。
测试被中断(超时、kill、并发跑挂掉)时 schema 不会删,开发库会越积越多。清理脚本:
deno run -A scripts/dev-db-clean.ts # dry-run:只打印清单
deno run -A scripts/dev-db-clean.ts --verbose # 同上,逐个列出 schema 名
deno run -A scripts/dev-db-clean.ts --yes # 真正删除
- 只在
DATABASE_URL(缺省postgres://umt:umt@localhost:55433/umt)指向 localhost:55433 时运行,否则直接拒绝。 - 删除的 schema:
tasks_test_、test_、e2e_、umt_test_、ao_test_、fm_test_、w2a_test_、w2b_、w7a_mig_、w9g_search_、server_test_前缀。public、openworkflow不动;有其它会话持锁的 schema(测试正在跑)跳过,但最好在没有测试运行时执行。 - 删除的 public 数据:名字以
w32-、w33-、fe4-、qa-开头的作品(title)、站点(name)、订阅(title_query),以及按 restrict 外键挂在它们下面的行,在一个事务里删。admin_user(w31-admin)、pi_upstream、没有这些前缀的站点(fake 上游)和手工登记的数据不动;要牵连到受保护表时脚本中止。
排障
配置无效:按提示检查.env,SECRET_MASTER_KEY至少 16 字符,DATABASE_URL必须是 postgres://。- health 返回
db: "down":docker compose -f docker-compose.dev.yml ps看容器健康状态。 deno check报找不到Deno:检查根目录是否误放了tsconfig.json(tsc 基座在config/tsconfig.base.json)。- tsc 报
Deno未定义:先跑deno task types生成types/deno.d.ts(已 gitignore)。 - 日志中的 passkey/token/cookie/authorization/password 字段与 URL query 参数会被替换为
[REDACTED](含logger.child()绑定字段与err的 message/stack);若发现明文,属于缺陷。