You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
packages/util/atomic-write/src/index.ts — holderExited()(if (pid === process.pid) return false)与 takeOverExitedLock() 只处理“PID 已不存在”的残留锁,注释中也写明:“A holder whose PID a live process reused keeps its lock until an operator removes it.” 这条保守策略正是本次无法自愈的原因:PID 没有复用,它一直活着,只是它的任务卡死了。
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Summary
DSH Desktop 0.2.2-rc.1:在「设置 → 插件」里做一次 bundle 开关,如果随后的 hot reload 没有结束,这次操作会永久占住 profile 的
package.json写锁,并堵死 HMR 的串行队列。此后所有插件安装/更新/卸载/开关,以及所有设置保存,都会一直转圈(约 120s 后报一次 writer lock 超时),用户没有任何办法自救,只能退出 DSH 重开。这类挂起不会自愈,因为锁的自动回收只认“记录的 PID 已经退出”,而记录在锁里的恰恰是仍然存活的宿主进程 PID。
Reproduction
dshmarket);package.json里的dsh.profile.bundles已经写入(目标 bundle 被移除),但cordis.patch.yml的 mtime 停在此前 —— 说明操作写完了清单,卡在 reload;atomic-write: timed out waiting for the writer lock at <profile>/package.json.lock;此时
~/.dsh/profiles/<profile>/package.json.lock的内容是宿主进程 PID(现场:43091,mtime 与package.json同为挂起时刻,之后 45 分钟未变动);.plugin-manager/logs/operation-*,registry 也通(单次安装 1–10s,exit=0);takeOverExitedLock生效,队列也随进程清空)。Current behavior
plugin-manager/operation诊断停留在started,不会走到settled/unknown。withFileLock上等lockWaitMs(默认 120000ms)才失败,看起来就像“点了没反应”。package.json.lock,后续操作仍会卡在hmr.runExclusive()的队列里 —— 删锁不重启不足以恢复。Expected behavior
failed,让 UI 能报错并重试;reconcileProfile加 deadline /AbortSignal);package.json.lock);Code pointers
packages/boot/plugin-manager/src/index.ts—change()在withFileLock(join(this.profile.dir, 'package.json'), async () => { ... await operation(result) ... }, { waitMs: this.lockWaitMs })内完成整个安装/更新/卸载/开关;锁只在 operation settle 后由finally释放,持有者没有任何超时。packages/boot/hmr/src/index.ts—runExclusive()中this.operations = task.catch(() => {}):一旦某个 task 永不 settle,后续所有调用都排在它后面(config-editor的保存、plugin-manager的configure()都走这条链)。packages/util/atomic-write/src/index.ts—holderExited()(if (pid === process.pid) return false)与takeOverExitedLock()只处理“PID 已不存在”的残留锁,注释中也写明:“A holder whose PID a live process reused keeps its lock until an operator removes it.” 这条保守策略正是本次无法自愈的原因:PID 没有复用,它一直活着,只是它的任务卡死了。lockWaitMs默认120000(packages/boot/plugin-manager/src/index.ts的Config)。Environment
0.2.2-rc.1(macOS 26.5.1 / arm64,App 内dsh0.2.2-rc.1)11.28.5,nodev26.3.1~/.dsh/profiles/desktop(nodeLinker: hoisted,7 个依赖 / 8 个 bundle 层,含社区 bundle)package.json.lock= 宿主 PID、mtime 15:10;package.jsonmtime 15:10 而cordis.patch.ymlmtime 15:03;.plugin-manager/logs/*/pnpm.log最后一条 15:09:27 成功、.dsh-market/log.ndjson同日 15:09 收尾;挂起后 45 分钟无子进程、无新增连接。Severity
阻断级但静默:用户能看到的现象只有「转圈」,既没有错误也没有日志入口;由于 profile 写锁是全局的,一个卡死的操作会连带禁用整个插件管理能力(以及设置保存),只能重启进程。
All reactions