Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

故障排查

按「先看日志、再定位子系统」的顺序排查问题。常见问题的快速解答见常见问题

第一步:看日志

如何调整日志详细程度?

日志级别与过滤由 RUST_LOG 环境变量控制(默认 info)。常用取值:

# 完整调试输出(更细可用 trace)
RUST_LOG=debug thurgio serve

# 只看订阅抓取流程(更新 + HTTP 客户端)
RUST_LOG="thurgio_app_update=debug,thurgio_request=debug" thurgio serve

# 只看数据库操作 / 模板渲染 / 配置热重载
RUST_LOG=thurgio_db=debug thurgio serve
RUST_LOG=thurgio_renderer=debug thurgio serve
RUST_LOG=thurgio_infra=debug thurgio serve

# 生产排障:安静模式
RUST_LOG="thurgio=info,warn" thurgio serve

日志在哪里看?

thurgio 把日志输出到 stdout/stderr:

  • systemd 部署:由 journald 收集,journald 自带容量与轮转管理,无需额外配置:
    journalctl -u thurgio -f              # 跟随最新日志
    journalctl -u thurgio -n 200          # 最近 200 行
    journalctl -u thurgio --since "1 hour ago"
    
  • 仅当你自行把日志重定向到文件时才需要配置 logrotate,示例见部署指南

需要结构化日志时设置 RUST_LOG_FORMAT=json,便于用 jq 过滤:

RUST_LOG_FORMAT=json thurgio serve | jq .

如何用 trace_id 追踪一次请求?

HTTP 错误响应的 JSON 体中带有 trace_id 字段。文本日志中直接搜索 trace_id= 即可定位同一次更新流程的全部日志;JSON 日志用 jq 过滤:

RUST_LOG_FORMAT=json thurgio serve | jq 'select(.fields.trace_id == 42)'

服务无法启动

报端口被占用怎么办?

默认监听 0.0.0.0:10100setting.address / setting.port)。找出占用端口的进程:

ss -ltnp 'sport = :10100'

然后停掉占用进程,或换端口启动(命令行参数优先于配置):

thurgio serve --address 127.0.0.1 --port 10200
# 等价环境变量:ADDRESS=127.0.0.1 PORT=10200 thurgio serve

配置解析错误起不来怎么办?

thurgio check

check 会解析完整配置并打印逐项检查结果,不访问网络、不写任何文件。如果是改配置改坏的,直接回滚:

thurgio config list
thurgio config restore <备份名>

config 命令不加载配置,坏配置下也能运行。更多配置陷阱(规则名拼错被静默忽略等)见常见问题

TLS 启动失败怎么办?

TLS 通过 --tls-cert / --tls-cert-key(或环境变量 TLS_CERT / TLS_CERT_KEY)启用。逐一排查:

# 1. 证书与私钥文件存在且进程用户可读
ls -l cert.pem key.pem
sudo -u thurgio head -c 64 /etc/thurgio/cert.pem

# 2. 同时提供明文与 HTTPS 时,--tls-port 必须与 --port 不同
thurgio serve --tls-cert cert.pem --tls-cert-key key.pem --tls-port 10443

# 3. --tls-only 要求证书与私钥同时提供,缺一会报错
thurgio serve --tls-only --tls-cert cert.pem --tls-cert-key key.pem

生产环境更常见的做法是让反向代理(nginx/Caddy)终止 TLS,thurgio 只监听 127.0.0.1,参见部署指南

提示数据库打不开或权限不足怎么办?

数据库位置由 DATABASE_URL 指定(默认相对数据根目录 -r/--rootthurgio.db),所在目录必须对运行用户可写:

ls -ld /var/lib/thurgio
sudo -u thurgio test -w /var/lib/thurgio && echo writable

可用公开端点确认数据库状态:GET /ready 在数据库可读时返回 200 {"status":"ready",...},不可读时返回 503 {"status":"not_ready","database":"disconnected"}

HTTP 错误码速查表

所有 API 错误以 JSON 返回,形如 {"error":"circuit_open","message":"...","kind":"CircuitOpen","status":503,"trace_id":42}。完整端点语义见 API 参考

状态码原因排查动作
401令牌无效/缺失,或作用域不足(Read 令牌访问 /app/admin/*);上游订阅源返回 401/403 时也会归入此类核对用的是 Read 还是 Admin 令牌组、请求的是哪个命名空间;用 POST /app/login 校验令牌作用域
403通常并非 thurgio 返回——多来自反向代理的访问控制(如限制 /metrics 的内网白名单)检查 nginx 的 allow/deny 或 Caddy 的 respond 403 规则
404资源不存在:provider/snippet 名字拼错,或该 provider 响应中没有可解析的流量元数据GET /app/read/subs 列出全部订阅名核对拼写
429超过速率限制(默认每 IP 每 60 秒 600 次)或并发限制,响应带 Retry-AfterRetry-After 等待后重试;降低客户端轮询频率;必要时用 THURGIO_RATE_LIMIT_REQUESTS / THURGIO_RATE_LIMIT_WINDOW_SECONDS 调整限额
500服务器内部错误(数据库/存储、模板渲染、内部异常)取响应体中的 trace_id 到日志中定位;检查模板语法与磁盘空间
502从上游订阅源抓取失败或超时(上游请求超时默认 9 秒,REQUEST_TIMEOUT 可调)且无缓存可回退直接 curl 上游 URL 验证可达性(DNS、网络、上游凭证)
503两种情况:渲染时熔断器已打开且无缓存可回退(kind: "CircuitOpen");或 GET /ready 报告数据库不可读前者见下节「订阅抓取失败」;后者检查数据库路径与磁盘

订阅抓取失败

上游挂了构建会失败吗?

不会立即失败。抓取失败时回退到数据库中的 last-known-good 缓存继续渲染;只有连缓存都没有时才会向上传播错误。

熔断器 open 是什么意思?

连续失败达到阈值(默认 5 次)后熔断器进入 open:一段时间内(基础 30 秒,带随机抖动)跳过该源不再发起请求,避免无效重试风暴。超时后进入 half-open 放行探测请求,探测成功即回到 closed。熔断器状态持久化到数据库,重启后恢复。

日志中搜索 circuit breaker 可以看到状态切换(如 circuit breaker opened after N failures、错误 circuit breaker open for <name>)。

如何观察各订阅源的健康状况?

curl "http://localhost:10100/app/read/health?token=my-token"

为每个 provider/snippet 报告熔断器状态(closed/open/half-open)、失败计数、最后失败时间与最后成功更新时间,并汇总为总体状态:healthy(无 open/half-open)、degraded(部分熔断)、unhealthy(全部 open)。

上游恢复了,如何让它立刻重试?

  • 等待半开探测自动恢复(无需干预);或
  • Admin 令牌强制刷新一次:GET /app/admin/refresh;或
  • GET /app/admin/sprov/url 请求头)更新源 URL——会同时重置该 provider 的熔断器并触发强制更新。

输出不更新

为什么改了上游但输出没变?

更新按 TTL 判断:缓存未过期时直接复用,不重新抓取。TTL 在 setting.ttl 中配置,默认 provider 600 秒(最小 60 秒)、snippet 86400 秒(最小 300 秒):

setting:
  ttl:
    provider: 600
    snippet: 86400

想立即刷新:

thurgio build --force        # 忽略缓存状态强制重新获取所有订阅源

服务运行时等价的 Admin 端点:GET /app/admin/refresh(仅更新)或 GET /app/admin/write(更新 + 渲染 + 写盘)。

为什么 --watch 下改动没有立即重建?

监听模式的变更事件经 500ms 防抖合并后才触发重建,属正常设计。另外它忽略构建自身的写入(输出目录与 SQLite 数据库文件),避免自触发循环。

为什么 serve 下改模板没生效?

serve 只监听主配置文件本身,模板变更不在监听范围内。两种解决方式:

# 方式一:开发模式启动(每次渲染前重新加载模板)
thurgio serve --dev

# 方式二:不重启,手动触发模板引擎重载
curl "http://localhost:10100/app/admin/reload?token=my-admin-token"

输出文件缺失、规则静默失效等其他「不生效」场景见常见问题

数据库问题

目录下的 thurgio.db-wal / thurgio.db-shm 是什么?

thurgio 以 SQLite WAL 模式运行数据库(支持多进程共享同一文件)。-wal-shm 是 WAL 模式的伴生文件,属于正常现象。不要在服务运行期间手动删除或移动它们——连同主库文件一起由 SQLite 管理,删除可能导致数据丢失。

怀疑磁盘空间不足怎么排查?

磁盘写满时数据库写入与输出文件发布都会失败,典型表现是请求返回 500Persistence 类错误)或 GET /ready 变为 503。排查:

df -h /var/lib/thurgio       # 检查数据库与输出所在分区
du -sh /var/lib/thurgio/*    # 定位大文件

清理出空间后,确认 /ready 恢复 200 即可;无需迁移数据。