npm install 也不是"锁上、跑一次、把结果统一返回给所有人",而是排队后每个人各跑一遍。真正合并成一次执行的只有一种很窄的情况。 下面分开说。 1… · @TanZeng1021 · TwKit
@TanZeng1021
npm install 也不是"锁上、跑一次、把结果统一返回给所有人",而是排队后每个人各跑一遍。真正合并成一次执行的只有一种很窄的情况。 下面分开说。 1. 没有给 LLM 的工具,拦截对 Agent 透明 Agent 用的就是它自带的 Bash 工具,照常敲 npm install。命令在 execve 那一层被拦下,路由到共享环境里的 command-gateway。排队和合并都由 gateway 根据命令本身判断,Agent 不知道自己在排队,只会觉得这条命令跑得久了一点。 假设 A、B 两个 Agent 同时执行 npm install: t0 A 拿到 "node-install" 锁,开始执行 t1 B 到达,排队等待(B 这边暂时没有输出) t2 A 跑完,拿到 A 自己的输出和退出码,释放锁 t3 B 拿到锁,真正执行一遍自己的 npm install (依赖通常已经装好,所以会很快,显示 up to date) t4 B 拿到 B 自己的输出和退出码 为什么不把 A 的结果直接返回给 B:npm install 这几个字说明不了全部输入。package.json 可能在两次之间被改过,lifecycle 脚本有副作用,两个人的 HOME、.npmrc、缓存也可能不同。把别人的结果当成自己的,可能是错的。 锁的范围宁可放宽,因为多锁一次只是慢一点;漏锁一次,冲突保护就没了。合并则必须精确,宁可不合并。 几个细节: 锁是按家族分的。npm、pnpm、yarn、bun 的安装类命令都属于 node-install,同一个 Sandbox 里同一时刻只跑一个。这会多锁一些本来不冲突的情况,代价是性能,换来的是正确。 排队有上限,默认 30 分钟。超时就放行,交给 npm 自己的并发机制,不会一直卡住。 别名都识别,比如 i、add、ci、update、rm,连 isntall 这种拼写错误也算。 前面带了 flag、套了 wrapper、用 npx、或者是不认识的子命令,都按原生行为执行,不加锁。 3. 唯一会合并的情况:npm ci --ignore-scripts 只有这一种形态会"搭车",而且条件很严: argv 必须完全一致,并且要显式关掉 lifecycle 脚本(--ignore-scripts),保证没有可观察的副作用。 输入指纹要完整:package.json、lockfile、项目 .npmrc、用户 npmrc、global config 都要算进去。缺 lockfile,或者配置路径解析不清,就退回只加锁。 必须是同一个 Linux 用户、同样的环境(环境变量做摘要)、非 TTY。跨用户合并在结构上就不可能,因为 key 里固定包含用户。 合并时的行为: 后来者在某个时间点原子地挂到正在跑的那一次上,从挂上去那一刻起开始收输出,最后拿到同一个退出码。 挂上去之前已经输出的内容不会补发。 拿到锁之后、真正启动之前,会重新算一遍指纹。如果文件已经变了,后来者会收到明确的拒绝,要求重试;先来的那个照常独立执行。 所以你说的"锁上、跑完、统一返回结果",只对这种情况近似成立。而且后来者拿到的输出是从中途开始的,不是完整的一份。
曝光 214 · 评论 0 · 点赞 0 · 书签 1
查看原帖