Fix credential cleanup and explicit tuning flags

This commit is contained in:
ZacharyZcR
2026-06-12 15:30:44 +08:00
parent 52f872b8d1
commit 5b7e72e56e
8 changed files with 205 additions and 86 deletions
+12 -5
View File
@@ -61,6 +61,8 @@ type AuthFunc func(ctx context.Context, cred Credential) *AuthResult
// ErrorClassifier 错误分类函数
type ErrorClassifier func(err error) ErrorType
var authCleanupWait = 2 * time.Second
// =============================================================================
// 单凭据测试(解决 goroutine 泄漏)
// =============================================================================
@@ -79,12 +81,17 @@ func TestSingleCredential(ctx context.Context, cred Credential, authFn AuthFunc)
case result := <-resultChan:
return result
case <-ctx.Done():
// context 被取消,等待 authFn goroutine 返回并清理连接
// 各插件的 authFn 应在 context 取消时关闭底层连接使 goroutine 快速退出
// context 被取消后只做有界等待,避免 authFn 卡死时清理 goroutine 也永久泄漏。
go func() {
result := <-resultChan
if result != nil && result.Conn != nil {
_ = result.Conn.Close()
timer := time.NewTimer(authCleanupWait)
defer timer.Stop()
select {
case result := <-resultChan:
if result != nil && result.Conn != nil {
_ = result.Conn.Close()
}
case <-timer.C:
}
}()
return &AuthResult{
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"io"
"runtime"
"sync/atomic"
"testing"
"time"
@@ -401,6 +402,40 @@ func TestTestSingleCredential_ContextCancel(t *testing.T) {
}
}
func TestTestSingleCredential_ContextCancelCleanupIsBounded(t *testing.T) {
oldWait := authCleanupWait
authCleanupWait = 20 * time.Millisecond
defer func() { authCleanupWait = oldWait }()
authStarted := make(chan struct{})
releaseAuth := make(chan struct{})
authFn := func(ctx context.Context, cred Credential) *AuthResult {
close(authStarted)
<-releaseAuth
return nil
}
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-authStarted
cancel()
}()
before := runtime.NumGoroutine()
result := TestSingleCredential(ctx, Credential{Username: "admin", Password: "admin"}, authFn)
if result.Success {
t.Error("context取消后不应该返回成功")
}
time.Sleep(100 * time.Millisecond)
after := runtime.NumGoroutine()
close(releaseAuth)
if after > before+1 {
t.Fatalf("清理 goroutine 疑似泄漏: before=%d after=%d", before, after)
}
}
// =============================================================================
// 重试逻辑测试
// =============================================================================