fix(runtime): treat a reused PID as a stale lock - #915
Open
edwardtoday wants to merge 1 commit into
Open
edwardtoday wants to merge 1 commit into
edwardtoday wants to merge 1 commit into
Conversation
clearStaleLock only checked processAlive on the recorded PID. After the lock holder is killed without a chance to clean up (SIGKILL, power loss, launchd exit timeout), the lock file stays behind. As soon as that PID is recycled by any unrelated process, processAlive stays true forever and the daemon can never acquire the lock again: it exits with "lock held by another process" on every start, which launchd's KeepAlive amplifies into a crash loop until the lock file is deleted by hand. The same function also returned an error instead of clearing the file when the lock JSON could not be parsed, so a lock truncated mid-write had the same permanent effect. Compare the holder's process start time with the lock creation time: the process that wrote the lock cannot have started after the lock was created, so a later start time means the PID was reused. Keep the previous behaviour when the start time is unavailable, and clear unparseable lock files. Start time lookups are implemented for darwin, linux and windows. Fixes kxn#913
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #913.
问题
clearStaleLock判断锁是否仍被持有时,只检查了processAlive(record.PID)。持有者被强杀(SIGKILL、断电、launchd 退出超时)后relayd.lock会残留下来;一旦该 PID 被系统复用给任意无关进程,processAlive就恒为真,daemon 每次启动都报配合
KeepAlive.SuccessfulExit=false,launchd 把它放大成崩溃循环,服务在人工删掉锁文件之前一直不可用(本机runs达到 7668,而实际上没有任何进程在运行)。出问题的锁记录的是pid=991,该 PID 随后被iCloudDriveService的ContainerMetadataExtractor.xpc复用。同一个函数还有第二条失效路径:锁文件无法解析时(例如写锁过程中被强杀导致 JSON 截断),它返回 JSON 错误而不是清理文件,同样是永久卡死。
修复
写锁的进程,其启动时间不可能晚于锁的创建时间;所以把持有者的进程启动时间和
record.CreatedAt比较,启动时间更晚即说明该 PID 已被复用,锁是陈旧的。unix.SysctlKinfoProc,linux 用/proc/<pid>/stat+btime,windows 用GetProcessTimes;其他平台保持原有行为测试
TestAcquireLockClearsLockWhosePIDWasReused—— 复现所报的卡死;在 master 上以lock held by another process失败TestAcquireLockClearsCorruptLockFile—— 在 master 上以unexpected end of JSON input失败TestAcquireLockFailsWhileLiveOwnerHoldsIt(既有测试)确认真正在运行的持有者仍被尊重已用
go test ./internal/runtime/验证,并额外通过GOOS=linux/GOOS=windows执行go vet ./internal/runtime/。备注
CI 里的
scripts/check/no-local-paths.sh在干净的master上同样失败(internal/core/orchestrator/service_target_picker_polluted_workspace_test.go中的/home/qagent/...不在 allowlist 内),与本 PR 无关。