From 00c53198198e78be3afb6afd8306e10723993807 Mon Sep 17 00:00:00 2001 From: xfy Date: Wed, 22 Apr 2026 13:35:03 +0800 Subject: [PATCH] =?UTF-8?q?refactor(proxy,server):=20=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E5=81=A5=E5=BA=B7=E6=A3=80=E6=9F=A5=20goroutine=20=E9=80=80?= =?UTF-8?q?=E5=87=BA=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - health: 使用 WaitGroup 确保 run goroutine 完全退出后再继续 - health_match: 忽略未使用参数,预分配 slice 容量 - proxy_coverage_extra_test: 使用 atomic.Int32 修复测试竞态条件 - purge: 忽略 Delete 返回值 Co-Authored-By: Claude Opus 4.7 --- internal/proxy/health.go | 7 ++++++- internal/proxy/health_match.go | 6 +++--- internal/proxy/proxy_coverage_extra_test.go | 17 +++++++++-------- internal/server/purge.go | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/internal/proxy/health.go b/internal/proxy/health.go index fd5f47c..6e47cdd 100644 --- a/internal/proxy/health.go +++ b/internal/proxy/health.go @@ -65,6 +65,7 @@ type HealthChecker struct { running atomic.Bool matcher HealthMatch // 健康检查匹配器 slowStartManager *loadbalance.SlowStartManager // 慢启动管理器 + wg sync.WaitGroup // 等待 run goroutine 退出 } // NewHealthChecker 使用指定的目标和配置创建一个新的 HealthChecker。 @@ -140,6 +141,7 @@ func (h *HealthChecker) Start() { if h.slowStartManager != nil { h.slowStartManager.Start() } + h.wg.Add(1) go h.run() } @@ -151,10 +153,11 @@ func (h *HealthChecker) Stop() { if !h.running.CompareAndSwap(true, false) { return // 已经停止,直接返回 } + close(h.stopCh) + h.wg.Wait() // 等待 run goroutine 退出 if h.slowStartManager != nil { h.slowStartManager.Stop() } - close(h.stopCh) // 重新创建 stopCh 以支持后续 Start h.stopCh = make(chan struct{}) } @@ -163,6 +166,8 @@ func (h *HealthChecker) Stop() { // 它对所有目标执行初始检查,然后进入循环, // 以固定间隔检查目标,直到被停止。 func (h *HealthChecker) run() { + defer h.wg.Done() + // 执行初始健康检查 h.checkAll() diff --git a/internal/proxy/health_match.go b/internal/proxy/health_match.go index f5e67bc..aacfa0f 100644 --- a/internal/proxy/health_match.go +++ b/internal/proxy/health_match.go @@ -42,7 +42,7 @@ type HealthMatch interface { type defaultHealthMatch struct{} // Match 实现 HealthMatch 接口。 -func (m *defaultHealthMatch) Match(status int, body []byte, headers map[string]string) bool { +func (m *defaultHealthMatch) Match(status int, _ []byte, _ map[string]string) bool { return status >= 200 && status < 300 } @@ -121,7 +121,7 @@ func NewHealthMatch(cfg *HealthMatchConfig) HealthMatch { } // 解析状态码范围 - var ranges []statusRange + ranges := make([]statusRange, 0, len(cfg.Status)) for _, s := range cfg.Status { r, err := parseStatusRange(s) if err != nil { @@ -142,7 +142,7 @@ func NewHealthMatch(cfg *HealthMatchConfig) HealthMatch { } // 解析响应头匹配 - var headerMatches []headerMatch + headerMatches := make([]headerMatch, 0, len(cfg.Headers)) for k, v := range cfg.Headers { headerMatches = append(headerMatches, headerMatch{ key: strings.ToLower(k), // 统一小写 diff --git a/internal/proxy/proxy_coverage_extra_test.go b/internal/proxy/proxy_coverage_extra_test.go index 2397e5a..decc9ad 100644 --- a/internal/proxy/proxy_coverage_extra_test.go +++ b/internal/proxy/proxy_coverage_extra_test.go @@ -20,6 +20,7 @@ import ( "net/http/httptest" "os" "strings" + "sync/atomic" "testing" "time" @@ -114,9 +115,9 @@ func TestHealthChecker_Run(t *testing.T) { }) t.Run("定时检查执行", func(t *testing.T) { - requestCount := 0 + var requestCount atomic.Int32 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestCount++ + requestCount.Add(1) w.WriteHeader(http.StatusOK) })) defer server.Close() @@ -135,15 +136,15 @@ func TestHealthChecker_Run(t *testing.T) { checker.Stop() // 应该至少执行初始检查 + 2 次定时检查 - if requestCount < 2 { - t.Errorf("期望至少 2 次检查,实际 %d 次", requestCount) + if requestCount.Load() < 2 { + t.Errorf("期望至少 2 次检查,实际 %d 次", requestCount.Load()) } }) t.Run("停止后不再检查", func(t *testing.T) { - requestCount := 0 + var requestCount atomic.Int32 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - requestCount++ + requestCount.Add(1) w.WriteHeader(http.StatusOK) })) defer server.Close() @@ -159,12 +160,12 @@ func TestHealthChecker_Run(t *testing.T) { checker.Start() time.Sleep(60 * time.Millisecond) checker.Stop() - countAfterStop := requestCount + countAfterStop := requestCount.Load() // 等待一段时间,确认不再有检查 time.Sleep(100 * time.Millisecond) - if requestCount != countAfterStop { + if requestCount.Load() != countAfterStop { t.Error("停止后不应再执行检查") } }) diff --git a/internal/server/purge.go b/internal/server/purge.go index 311f5e2..2ff0c75 100644 --- a/internal/server/purge.go +++ b/internal/server/purge.go @@ -204,7 +204,7 @@ func (h *PurgeHandler) purgeByPath(path string, method string) int { for _, p := range h.server.proxies { if pcache := p.GetCache(); pcache != nil { - pcache.Delete(hashKey) + _ = pcache.Delete(hashKey) deleted++ } }