RealTime 레지스트리 동시성 테스트 + CI race detector - #218
Merged
Conversation
realtime/CLAUDE.md §11 은 동시성 검증에 `go test -race` 를 규정하는데 CI 는 `go test ./...` 로만 돌고 있었다. 본업이 동시 fan-out 인 컴포넌트에서 경합은 여기서 못 잡으면 운영에서 간헐적 패닉·유실로만 드러난다. 그런데 -race 를 켜도 잡을 게 있으려면 동시 접근을 실제로 만드는 테스트가 있어야 한다. Registry 는 서버 전체의 공유 가변 상태이고 운영에서는 AMQP 컨슈머가 Dispatch 하는 동안 HTTP 핸들러들이 Subscribe/Unsubscribe 하는데, 기존 테스트 2개는 모두 순차 실행이었다. Dispatch 는 의도적으로 락을 놓은 뒤 채널에 쓴다(느린 구독자가 락을 잡으면 다른 구독자까지 막히므로). 그 설계상 "복사한 목록"과 "지금 살아있는 구독자"가 어긋나는 창이 생긴다 — 그 창에서 자료 경합이 없는지, 그리고 churn 중 id 기반 제거가 어긋나 해제된 구독자가 목록에 남지 않는지 확인한다. Makefile 에 test-race 타깃도 추가 — push 전 로컬 확인용.
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.
왜
realtime/CLAUDE.md §11은 동시성 검증에go test ./... -race를 규정한다. CI 는-race없이 돌고 있었다.RealTime 은 본업이 동시 fan-out 인 컴포넌트다 — AMQP 컨슈머 고루틴이
Dispatch하는 동안 HTTP 핸들러들이Subscribe/Unsubscribe한다. 여기서 경합을 못 잡으면 운영에서 간헐적 패닉·이벤트 유실로만 드러나고, 재현이 거의 불가능하다.다만
-race를 켜는 것만으로는 부족했다. 잡을 게 있으려면 동시 접근을 실제로 만드는 테스트가 있어야 하는데,Registry테스트 2개는 모두 순차 실행이었다. 서버 전체의 공유 가변 상태인데도.무엇
1. 레지스트리 동시성 테스트
8개 고루틴이 Subscribe→읽기→Unsubscribe 를 200회씩 돌리는 동안 4개 고루틴이 계속 Dispatch 한다.
겨냥하는 지점은
Dispatch의 설계다 — 구독자 목록을 락 아래서 복사한 뒤 락을 놓고 채널에 쓴다(느린 구독자가 락을 잡고 있으면 다른 구독자까지 막히므로 의도된 설계다). 그래서 "복사한 목록"과 "지금 살아있는 구독자"가 어긋나는 창이 구조적으로 존재한다.-race)Dispatch가 0 을 반환하는지로 확인2. CI 에
-racego test -race ./.... 기존 Go 잡은 15~21초라 여유가 있다.3.
make test-raceCI 와 같은 형태를 로컬에서 돌릴 수 있게. 동시성 코드를 건드렸으면 push 전에 이걸로 확인한다.
함께 읽었고 문제없던 것
이번에 RealTime 동시성 경로를 훑었는데, 아래는 모두 이미 잘 처리돼 있었다.
Dispatchtime.After였다면구독자×이벤트만큼 타이머 고루틴 누수)ws.godone채널로 writeLoop 종료. defer 순서가close(done)→Unsubscribe→CloseNow로 정확ws_audio.goerrc버퍼 2 — 한쪽이 끝나 핸들러가 반환해도 나머지 고루틴이 채널 전송에서 막히지 않는다. 양쪽 conn 이 닫히며Read가 풀려 종료즉 이 PR 은 발견한 버그를 고치는 게 아니라, 지금의 무결함 상태를 회귀로부터 고정하는 것이다.
검증
로컬에 Go 툴체인이 없어 CI 로 검증한다. 이 PR 의 Go 잡이 통과하면 (a) 테스트가 컴파일·통과하고 (b) 현재 코드가 race-free 임이 함께 확인된다. 잡이 빨개지면 실제 경합을 찾은 것이므로 그때 고친다.