← 返回文章选择

MediAC 启动记录:先看 ready 返回了什么

四个容器都 running 了,API 连得上吗?一个只查连通性的 ready 接口,和三个数据库各自的就绪问法。

这一阶段先不做页面,把启动步骤走通。项目用 API、Postgres、Qdrant 和 Neo4j 四个容器;后面要比较文本检索和图检索,两套数据服务都先留下。

启动入口尽量短

README 里的第一步:

Terminal window
cp .env.example .env

复制后还得编辑模型 key 和连接配置,再启动:

Terminal window
docker compose up -d --build
curl http://localhost:8000/health/ready

running 之后,再问一句连得上吗

docker compose ps 里看到 running,我还想再问一步:API 能连上这几个服务吗?端口开始监听和数据库可用并不总是同时发生,地址也可能配错。于是保留一个只检查连通性的 ready 接口,先把问题缩小到连接这一层。

Compose 文档也是这么写的:启动时它只等容器在跑,不等容器可用(Compose 启动顺序)。docker compose ps 默认也只列正在运行的容器,退出过的不加 -a 根本看不到,健康状态也不在默认表格里(compose ps 参考)。

九月整理代码时,backend/main.py 里的检查就三项:

  • Postgres 执行 SELECT 1
  • Qdrant 请求 /collections
  • Neo4j 执行 RETURN 1 as ok

返回里分别列三项结果,有一项失败,整体状态就是 degraded。这些是整理时的实现细节,方便对照接口读代码。

postgres = true
qdrant = false
neo4j = true
→ status = degraded

API 检查三个服务,Qdrant 失败使整体状态降级

这是一个说明用的返回。示例里只有 Qdrant 那项失败:整体状态看不出是哪一条没连上,分项结果能指出来,但不能由此认定问答流程已经部分可用。

遇到这种情况,我会先查 API 配的 Qdrant 地址和服务响应,不急着换 embedding 模型。连通性恢复以后,再查 collection 有没有资料、向量维度对不对。ready 不调用问答模型,也不验证资料是否入库,绿色结果只说明到这一层。

三个数据库,三种就绪问法

为什么三项检查各写各的?因为三家官方给的东西本来就不一样:

服务 官方提供的检查 它回答的问题
Postgres pg_isready,退出码 0 正常、1 拒绝连接(如启动中)、2 无响应 服务器收不收连接;不要求正确的用户名、密码和库名(pg_isready 文档)
Qdrant /healthz 和 /readyz 两个端点 实例活着,以及能不能开始接流量(Qdrant readyz 参考)
Neo4j Docker 文档里没有现成探针,只建议浏览器打开 7474 试连 只能自己发一条 Cypher(Neo4j Docker 文档)

对照这张表,SELECT 1 比 pg_isready 多查了一层:用这套凭据能连上,库也在。端口通了而密码错了,恰好落在 ready 要覆盖的那段窗口里。Neo4j 那条 RETURN 1 as ok 也是官方工具 cypher-shell 的正常用法,走一次真实的 Bolt 连接再执行一次查询(cypher-shell 文档)。

查 Qdrant 地址时还有个小坑:它默认 REST 走 6333、gRPC 走 6334,两个端口写混是另一类故障;默认也不开认证,所以连不上一般不是权限问题(Qdrant Quickstart)。等连上之后查维度,依据也很硬:同一个 collection 里所有向量维度必须一致(Qdrant Collections)。

按 Kubernetes 的分法,这个接口属于 readiness,不是 liveness:readiness 失败只是不接流量,liveness 失败才重启,后端依赖是否可用应该放在 readiness 里查(Kubernetes 探针文档)。ready 变红时,该做的是停下来查连接,重启容器帮不上忙。

配置在哪儿被读,最容易混

配置集中交给 pydantic-settings,变量名列在 .env.example。容易混的是文件在哪儿被读:Compose 先用变量处理部署配置,API 进程再读取自己的环境。宿主机里的一份 .env,不会因为放在目录里就自动成为所有容器的配置。Compose 文档的说法是:容器的环境变量必须在服务配置里显式写上才会进去,项目目录里的 .env 只用于插值(Compose 环境变量)。

pydantic-settings 这边也有两条容易踩:环境变量永远比 dotenv 文件优先;只给文件名时,它只在当前工作目录找 .env,不往上层目录找(pydantic-settings 的 dotenv 一节)。文件放在哪个目录,和进程从哪个目录启动,是两件事。Pydantic Settings 文档可以对照读取规则,实际路径还要按启动方式看。

哪一步没过,就停在哪一步

项目用 .dockerignore 把不用的文件挡在构建上下文外。这个文件只在构建上下文的根目录生效,挪了目录会悄悄失效(Docker 构建上下文)。新环境按顺序检查:

  1. 启动
  2. 请求 ready
  3. 导入数据

哪一步没过就停在哪一步查,比等最终问答报错再回头查四个服务省事。这三步有依赖:连接配置或模型 key 在启动那一步写错,导入数据多半也会失败,那时看到的位置和真正的原因往往已经不在一处。

如果不想自己写 ready,Compose 也有一套:给服务配 healthcheck,依赖方用 depends_on 的 condition: service_healthy 等它通过(Compose services 参考),或者直接 docker compose up --wait,等所有服务 running 或 healthy 再返回(compose up 参考)。代价是检查命令跑在容器里,要求镜像里有对应的客户端工具,而且查的是服务自己好不好,不是 API 用自己的配置连不连得上。我更看重后一个问题,所以 ready 留在应用里。

留下几句话 读者来信

读到这里,有什么想法?欢迎留下你的看法。