Satis本身不支持高可用,因其是无状态静态生成器;高可用需通过集中构建+共享存储同步至多台Nginx节点,并配置健康检查与负载均衡实现。

satis build 本身无法做负载均衡
因为 satis build 是一次性静态生成操作,不监听端口、不维持状态、不处理任何 HTTP 请求。你给它加再多台机器跑 satis build,也不会自动同步或协调——每台都只是独立输出一份 packages.json 和 dist/ 文件。所谓“高可用”,从来不是让 Satis 自身集群化,而是让它产出的静态文件,在多台 Web 节点上保持一致且可切换。
- 别在 CI 流水线里并发执行
satis build到不同节点:路径、Git 凭据、tag 解析顺序稍有差异,就会导致各节点packages.json内容不一致 - 构建必须集中一次完成,再通过原子同步方式(如
rsync --delete-after+--delay-updates)推送到所有 Web 节点的共享挂载点 - 若用 NFS/S3/MinIO 作共享存储,所有 Nginx 节点的
root必须指向同一路径,否则packages.json里的dist.url会指向一个实际不存在的 ZIP
Nginx upstream 健康检查必须精准有效
只写 upstream satis { server 10.0.1.10; server 10.0.1.11; } 没用。Composer 客户端发的是短连接、无 session 的并发请求,Nginx 若不能快速识别并剔除故障节点,composer install 就会随机卡在 Downloading (connecting)。
- 启用
max_fails=2 fail_timeout=30s,避免瞬时网络抖动误判为宕机 - 用
location = /packages.json作为健康探针路径:轻量、可缓存、响应快,且能真实反映静态文件是否可读 - 所有节点返回的
Content-Type必须是application/json,Nginx 配置里要显式声明types { application/json json; },否则 Composer 解析失败但 HTTP 状态码仍是 200,上游不会被踢出 - 禁用
ip_hash:Composer 并发请求无粘性,会导致流量倾斜,某节点过载而其他空闲
dist 包 URL 配错会导致全部下载卡死
"archive": {"prefix-url": "https://cdn.example.com/dist/"} 这个字段看着简单,填错一个字符,所有私有包的 --prefer-dist 就会失效。Composer 不会报错,只会默默卡在 Downloading (connecting),直到超时回退到 git clone。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
-
prefix-url必须以/dist/结尾(注意末尾斜杠),否则生成的 ZIP URL 会变成https://cdn.example.comdist/xxx.zip - 该域名必须可被 CI 构建容器、Docker 宿主机、开发机 DNS 解析并连通;不能填
localhost或未配置/etc/hosts的短域名 - CDN 或对象存储需开启 CORS:
Access-Control-Allow-Origin: *,否则 GitLab Runner with Docker-in-Docker 等环境会因跨域拒绝下载 - 别用 GitHub Pages 托管 dist:它不支持自定义 MIME 类型,ZIP 响应头可能是
text/plain,触发 Composer 校验失败
客户端 composer.json 必须禁用 packagist.org 回退
最隐蔽的翻车点:项目 composer.json 里写了私有源,但没关掉默认回退,结果 composer require company/internal-lib 成功了,composer update 却悄悄从 packagist.org 拉了个同名但非审计版本的包——因为 Satis 没索引那个版本,Composer 自动 fallback 了。
- 必须显式关闭公共源:
"repositories": [{"type": "composer", "url": "https://satis.internal/packages.json"}, {"packagist.org": false}] - 这个配置必须写在项目根目录的
composer.json里,不是全局配置,也不是 Satis 自己的配置文件 - CI 流水线中建议加校验步骤:
composer show --format=json | jq '.repositories[] | select(.url and .type=="composer")',确保私有源生效且唯一
真正容易被忽略的,是 packages.json 和 dist/ 文件之间的时间一致性——哪怕同步延迟 1 秒,某个请求拿到新 packages.json 里写的 ZIP URL,却还没同步到对应 ZIP 文件,就会直接失败。所以共享存储的原子写入、Nginx 缓存策略、以及构建后同步的顺序,比选什么负载均衡器更关键。

















