From c84fea9ef07ea7aaba23b0fb474a108b2004e5d5 Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Sun, 16 Aug 2026 18:55:15 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=B0=E8=B4=A6:=20Recorder=20Close=20?= =?UTF-8?q?=E5=B9=82=E7=AD=89=E9=98=B2=E9=87=8D=E5=A4=8D=E5=85=B3=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - main 的 defer Shutdown 与显式 Close 双调用导致停机 panic close of closed channel - 用 sync.Once 保证只关闭一次 Co-Authored-By: Claude --- server/internal/usage/usage.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server/internal/usage/usage.go b/server/internal/usage/usage.go index 84f1a94..6dbeb50 100644 --- a/server/internal/usage/usage.go +++ b/server/internal/usage/usage.go @@ -18,6 +18,7 @@ type Recorder struct { ch chan *store.UsageLog wg sync.WaitGroup closed chan struct{} + once sync.Once // 保证 Close 只执行一次(main 的 defer Shutdown 与显式 Close 双调用) } const batchSize = 32 @@ -45,9 +46,11 @@ func (r *Recorder) Record(l *store.UsageLog) { } func (r *Recorder) Close() { - close(r.closed) - r.wg.Wait() - close(r.ch) + r.once.Do(func() { + close(r.closed) + r.wg.Wait() + close(r.ch) + }) } func (r *Recorder) run() {