Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-push-registry

직접 겪은 "푸시 0건" 버그를 Go 동시성 시나리오로 재현하고, race detector로 검증한 뒤 수정한 학습 프로젝트.

문제

Java/Spring으로 만든 복약 관리 서비스에서, 다른 유저가 같은 푸시 토큰을 재등록하면 소유권이 이전되지 않아 새 유저에게 알림이 0건이 되는 버그를 겪었다. 같은 문제를 Go로 옮겨 재현하고, 테스트로 고정한 뒤 고쳤다.

재현과 수정

커밋 히스토리가 순서 그대로 서사다.

  1. naive store: goroutine 100개가 동시 등록하면 go test -race에서 DATA RACE 검출, 재등록 시 소유자가 갱신되지 않는 버그를 테스트로 고정
  2. sync.Mutex 보호 + 명시적 소유권 이전(이전 소유자를 반환값으로 보고)으로 수정, -race 통과
  3. channel 큐 + 워커 풀 + 가짜 Sender로 발송 경로 구성, 50건 전량 발송 검증

실행

go test -race ./...

스코프와 의도적 한계

  • in-memory 저장소. 주제가 저장소가 아니라 동시성이라서
  • 실제 FCM 연동 없음. Sender 인터페이스와 가짜 구현으로 대체
  • 백프레셔(큐 가득 시 503), graceful shutdown은 다음 단계

설계 결정

  • 상태 보호는 Mutex, 작업 전달은 channel. 토큰 맵을 채널 액터(소유자 goroutine + 요청 채널)로 만드는 대안을 검토했지만, 읽기마다 답장 채널을 동봉하는 왕복 비용과 코드량 대비 얻는 것이 없어 기각
  • 인터페이스는 Sender 하나만. 테스트 대역이 실제로 필요한 자리에만 두고, 구현이 하나뿐인 저장소 인터페이스는 만들지 않았다
  • 워커 종료는 close + WaitGroup 드레인. 테스트에서 time.Sleep 동기화는 쓰지 않는다

AI 협업

Claude Code와 함께 개발했다. 설계 결정과 검증 시나리오는 직접 정했고, 조립 성격의 코드는 AI 초안을 검토 후 채택했다. 초안을 뒤집은 예: AI는 조회 메서드를 공개(UserOf)로 제안했지만, 단일 패키지라 노출할 이유가 없어 비공개(userOf)로 유지했다.

아는 것 / 아직 모르는 것

  • 아는 것: goroutine, channel과 Mutex의 용도 구분, WaitGroup, race detector, 테이블 드리븐 테스트
  • 아직 모르는 것: GC와 스케줄러 내부, pprof 프로파일링, 제네릭 실전, 대규모 Go 코드베이스의 관례

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages