streamplace에 기여하기
Source: Dev.to
프로젝트를 찾게 된 계기
요즘 저는 Go 코드를 꾸준히 읽고 쓰고 있으며, 제 Go 여정은 A Tour of Go부터 시작했습니다. http-server-ts를 만들면서 이 영상을 보았는데, Primeagen이 Go로 HTTP 서버를 구축하는 모습을 통해 Go가 네트워크 프로그래밍을 어떻게 다루는지 알게 되었습니다. 언어에 대한 자신감이 붙자 streamplace를 발견했습니다. 그곳의 issue를 해결했고, 성공적으로 PR을 머지했습니다. 자세한 내용은 아래에 적어두었습니다.
이슈 설명
firehose가 사용 불가능할 때, 스트림에는 루프를 크래시시키는 오류가 있었습니다. 코드를 직접 셋업하지도 않고 (C++ 배경 덕분에) 코드베이스에 익숙해진 뒤, 해당 이슈에 “작업하고 싶다”는 댓글을 달았습니다. 문제는 labeler_firehose.go 파일의 StartLabelerFirehose() 함수에 있었으며, 저는 크래시를 백오프 메커니즘으로 교체하려고 했습니다. 유지보수 담당자로부터 “접근 방식이 타당해 보이며, spmetrics.go에 메트릭을 추가하는 것이 좋겠다”는 좋은 피드백을 받았습니다. 기본적으로 유지보수 담당자와의 대화가 PR의 왕복을 줄여 주었고, 이는 모두에게 권장하고 싶은 방법입니다: 이슈를 착수하기 전에 미리 소통하세요.
셋업
코드 구조가 꽤 특수했지만, 의존성 처리 때문에 프로젝트를 설정하는 데 시간이 많이 걸렸습니다. 정기적으로 기여하려면 더 일찍 이 작업을 해 두었어야 했는데, 저는 너무 많은 시간을 소비했습니다. 문서를 따라가다 보니 sqlite3 버전 문제도 겪었습니다.
해결 방안
spmetrics.go에 streamplace_labeler_firehoses_connected 메트릭을 추가해 라벨러 연결 수를 추적했습니다:
var LabelerFirehosesConnected = promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "streamplace_labeler_firehoses_connected",
Help: "number of currently connected labeler firehoses",
}, []string{"labeler"})
그 후 spmetrics.go를 임포트하고, 재시도 임계값에서 로그 레벨을 Error에서 Warn으로 바꿨습니다:
log.Warn(ctx, "firehose failed 3 times within a minute, backing off", "err", err)
time.Sleep(5 * time.Second)
retryCount = 0
retryWindow = time.Now()
버그를 고치는 과정에서 cancel()을 바꾸면서 레이스 컨디션을 처음 도입했습니다:
defer func() {
spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Set(0)
cancel()
}()
defer는 함수가 반환될 때까지 실행되지 않으며, 별도로 defer cancel()도 있었기 때문에 혼란이 생겼습니다. 저는 원래의 defer cancel()을 유지하고 수정하지 않기로 했습니다.
유지보수 담당자의 테스트 및 제안
Bluesky 공식 모더레이션 라벨러를 사용해 로컬에서 변경 사항을 테스트했습니다. 라벨러 firehose가 연결된 동안 메트릭이 1을 보고하고, 반복 실패 시 5초 동안 백오프하면서 크래시가 발생하지 않는 것을 확인했습니다.
처음에는 이렇게 작성했습니다:
spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Set(1)
defer spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Set(0)
유지보수 담당자는 다중 라벨러 firehose를 지원하기 위해 Inc와 Dec를 사용할 것을 제안했습니다:
spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Inc()
defer spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Dec()
결국 제 PR이 머지되었습니다.
얻은 지식
처음으로 잘 구조화된 Go 코드베이스를 다뤄보았습니다. 레이스 컨디션에 대해 배우게 되었고, 작은 디테일이 얼마나 중요한지 다시 한 번 깨달았습니다. 또한 앞서 언급했듯이, 코드 변경은 정확하게 유지하고 유지보수 담당자와 지속적으로 소통하는 것이 좋습니다. 앞으로도 계속해서 이 코드베이스에 기여해 나가겠습니다.