为 streamplace 做贡献
Source: Dev.to
我是如何发现这个项目的
如今,我经常阅读和编写 Go 代码,我的 Go 之旅始于 A Tour of Go。在构建我的 http-server-ts 时,我观看了这段视频,Primeagen 在其中用 Go 构建了一个 HTTP 服务器,这让我了解了 Go 如何处理网络编程。在对语言特性有了信心后,我找到了 streamplace。我处理了那个 issue 并成功提交了一个被合并的 PR。下面给出详细过程。
Issue 描述
当 firehose 不可用时,流中有易出错的代码会导致循环崩溃。熟悉代码库后(甚至没有搭建环境,得益于我的 C++ 背景),我在 issue 下评论说想要处理它。我指出问题出现在 labeler_firehose.go 中的 StartLabelerFirehose() 函数,并计划用退避机制取代崩溃。维护者给了我很好的反馈,认为我的思路合理,并建议在 spmetrics.go 中添加一个指标。基本上,我与维护者的交流减少了 PR 中的来回讨论,我推荐大家在处理 issue 前先沟通一下。
环境搭建
虽然代码结构相当小众,但由于依赖处理,搭建该项目耗时很长。我在这上面花了太多时间,本应该早些完成,以便以后能定期贡献。我在按照文档操作时遇到了 sqlite3 版本问题。
解决方案
我通过在 spmetrics.go 中添加 streamplace_labeler_firehoses_connected 指标来跟踪 labeler 连接:
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()
在修复此 bug 时,我最初通过修改 cancel() 引入了竞争条件:
defer func() {
spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Set(0)
cancel()
}()
defer 直到函数返回才会执行,而我还有另一个单独的 defer cancel(),导致混乱。于是我决定保留原来的 defer cancel(),不再修改它。
测试与维护者的建议
我在本地使用 Bluesky 官方的 moderation labeler 进行测试。验证了在 labeler firehose 连接时指标显示为 1,并且在重复失败后重试路径会退避 5 秒而不是崩溃。
最初我写的是:
spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Set(1)
defer spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Set(0)
维护者建议使用 Inc 和 Dec 来支持多个 labeler firehose:
spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Inc()
defer spmetrics.LabelerFirehosesConnected.WithLabelValues(did).Dec()
最终我的 Pull Request 被合并。
收获的知识
这是我第一次接触结构良好的 Go 代码库。我了解了竞争条件,并再次提醒自己细节的重要性。此外,正如前面所说,保持代码改动精准并与维护者保持联系更为有效。我会继续前进,持续为该代码库贡献代码。