Skip to content

fix(crewmail): 쪽지 선점을 mkdir 게이트로 — 윈도우 rename 동시 성공(이중 배달) 근본 수정 - #237

Open
beyondworks wants to merge 4 commits into
mainfrom
fix/crewmail-claim-windows
Open

fix(crewmail): 쪽지 선점을 mkdir 게이트로 — 윈도우 rename 동시 성공(이중 배달) 근본 수정#237
beyondworks wants to merge 4 commits into
mainfrom
fix/crewmail-claim-windows

Conversation

@beyondworks

Copy link
Copy Markdown
Owner

배경 — 윈도우 CI 간헐 실패 (run 31085690668)

test/crewmail.test.mjs "선점 경합" 테스트가 windows-latest에서 간헐 실패(actual 2 !== expected 1 — 이중 배달). 제보 가설 ①(윈도우 rename 의미론 차이 = 진짜 제품 결함) / ②(테스트 플레이크) 중 ①로 확정.

근본 원인 (윈도우 CI 직접 재현으로 실증)

  • 선점은 rename(msg.json → msg.json.claimed) 단독 — "rename은 원자적이라 승자 1명" 전제.
  • 이 전제가 윈도우에서 거짓. libuv는 이름 기반 MoveFileExW 단일 호출이지만(v1.51 원문 대조), **MoveFileEx 자체가 내부적으로 "소스 핸들 열기 → 핸들 기반 rename"**이라, 두 호출이 겹치면 둘 다 rename 전에 소스 핸들을 열고 — 핸들은 파일을 따라가므로 — 둘 다 성공한다.
  • windows-latest 실측: 같은 소스→같은 타깃 동시 rename 2000회 중 1999회 이중 성공(POSIX는 커널 이름 기준 원자 처리라 패자 ENOENT). 실경로(deliverCrewMail 2개 동시)는 483/500 이중 배달. CI "간헐"은 두 rename의 시간적 겹침 여부일 뿐.

수정

  • 선점을 mkdir 게이트 + rename으로: 디렉터리 생성은 윈도우·POSIX 모두 이름 기준 원자(패자 EEXIST)라 게이트가 claim rename의 동시 실행 자체를 막는다 → 핸들 경합 창이 열리지 않음.
  • 게이트 크래시 잔재는 CLAIM_STALE_MS(45분) 경과 시 회수 — 메시지 영구 잠김 방지.
  • 스캔(pendingBySlug)은 .json/.claimed 접미만 보므로 .gate는 배달 대상에 혼입되지 않음.

테스트

  • 경합 테스트를 30회 반복으로 강화 — 단발은 겹침이 안 난 회차가 통과해 플레이크로 남는다(회차당 윈도우 이중 배달률 ~97% 실측이므로 반복이면 결정적 트립와이어).

검증 (windows-latest 직접 실행, run 31087493311)

  • 수정 후 실경로 이중 배달 0/500 (수정 전 483/500)
  • 전체 테스트 스위트 윈도우 그린 (macOS 로컬 866케이스 그린)
  • 변이 프로브: 게이트를 제거해 출하본 선점으로 되돌리면 강화된 테스트가 윈도우에서 red — 테스트가 결함을 실제로 잡음을 확인 후 변이 폐기
  • 불변식 변경 전수 수색: rename을 상호배제로 쓰는 곳은 crewmail 선점 1곳뿐(나머지는 보관 이동·유니크 타깃·원자 교체 용법)

기각한 가설

  • ② 테스트 경합 설계 문제(플레이크) — 테스트는 옳았고, 오히려 단발이라 결함을 간헐로만 노출
  • libuv 핸들 기반 rename 구현 — v1.51.0·Node 22 vendored 소스 모두 이름 기반 MoveFileExW 확인(TOCTOU는 MoveFileEx 내부)

🤖 Generated with Claude Code

beyondworks and others added 4 commits August 6, 2026 17:55
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant