fix: resolve golangci-lint issues across multiple packages

- stream: fix atomic.Int64 usage in tests and benchmarks
- server: fix errcheck, goconst ("tcp" -> constant), and govet shadow
- app: add missing ServerModeAuto case in requiresFullRestart
- lua: fix nolintlint unused directive warnings
- proxy: use `any` instead of `interface{}`
This commit is contained in:
xfy 2026-06-03 18:17:07 +08:00
parent 6f17bbad7e
commit 29752f62bd
8 changed files with 47 additions and 38 deletions

View File

@ -192,7 +192,7 @@ func (a *App) reloadConfig() {
for i, ln := range listeners {
duped[i], err = server.DupListener(ln)
if err != nil {
for j := 0; j < i; j++ {
for j := range i {
_ = duped[j].Close()
}
a.logger.Error().Err(err).Msg("Failed to dup listener for reload")
@ -289,6 +289,8 @@ func (a *App) requiresFullRestart(newCfg *config.Config) bool {
return true
}
}
case config.ServerModeAuto:
return true
}
return false
}

View File

@ -180,7 +180,7 @@ func RegisterLocationAPI(L *glua.LState, manager *LocationManager, ngx *glua.LTa
optionsTable := L.CheckTable(2)
optionsTable.ForEach(func(key, value glua.LValue) {
keyStr := glua.LVAsString(key)
//nolint:exhaustive // 只处理特定类型
//nolint:exhaustive,nolintlint
switch value.Type() {
case glua.LTString:
opts[keyStr] = glua.LVAsString(value)

View File

@ -308,7 +308,7 @@ func (api *ngxReqAPI) luaSetURIArgs(L *glua.LState) int {
// 获取参数类型
argType := L.Get(1)
//nolint:exhaustive // 只处理特定类型
//nolint:exhaustive,nolintlint
switch argType.Type() {
case glua.LTString:
// 如果是字符串,直接解析并设置
@ -330,7 +330,7 @@ func (api *ngxReqAPI) luaSetURIArgs(L *glua.LState) int {
table.ForEach(func(key, value glua.LValue) {
keyStr := glua.LVAsString(key)
//nolint:exhaustive // 只处理特定类型
//nolint:exhaustive,nolintlint
switch value.Type() {
case glua.LTString:
// 类型断言检查

View File

@ -57,7 +57,7 @@ import (
// proxyDebugLog 在 DEBUG 级别记录代理日志
// 调用者必须先检查 logging.Debug().Enabled() 以避免不必要的内存分配
func proxyDebugLog(msg string, kv ...interface{}) {
func proxyDebugLog(msg string, kv ...any) {
event := logging.Debug()
for i := 0; i < len(kv)-1; i += 2 {
key, ok := kv[i].(string)

View File

@ -46,6 +46,8 @@ import (
"rua.plus/lolly/internal/version"
)
const networkTCP = "tcp"
// Server HTTP 服务器,封装 fasthttp.Server 并提供中间件链和生命周期管理。
//
// 该结构体是服务器的核心实体,负责:
@ -358,7 +360,7 @@ func (s *Server) createListener(cfg *config.ServerConfig) (net.Listener, error)
return listener, nil
}
return net.Listen("tcp", listenAddr)
return net.Listen(networkTCP, listenAddr)
}
func (s *Server) matchInheritedListener(inherited []net.Listener, listenAddr string) net.Listener {
@ -383,7 +385,7 @@ func (s *Server) matchInheritedListener(inherited []net.Listener, listenAddr str
if ln == nil {
continue
}
if ln.Addr().Network() != "tcp" {
if ln.Addr().Network() != networkTCP {
continue
}
if s.tcpAddrMatch(ln.Addr().String(), listenAddr) {
@ -426,14 +428,14 @@ func DupListener(ln net.Listener) (net.Listener, error) {
if err != nil {
return nil, fmt.Errorf("dup tcp listener: %w", err)
}
defer file.Close()
defer func() { _ = file.Close() }()
return net.FileListener(file)
case *net.UnixListener:
file, err := l.File()
if err != nil {
return nil, fmt.Errorf("dup unix listener: %w", err)
}
defer file.Close()
defer func() { _ = file.Close() }()
return net.FileListener(file)
default:
return nil, fmt.Errorf("unsupported listener type: %T", ln)
@ -467,8 +469,8 @@ func (s *Server) startSingleMode() error {
if err != nil {
logging.Error().Msg("Failed to create status handler: " + err.Error())
} else {
if err := s.locationEngine.AddExact(statusHandler.Path(), statusHandler.ServeHTTP, false); err != nil {
if err := s.handleRegistrationError("status", statusHandler.Path(), err); err != nil {
if regErr := s.locationEngine.AddExact(statusHandler.Path(), statusHandler.ServeHTTP, false); regErr != nil {
if err := s.handleRegistrationError("status", statusHandler.Path(), regErr); err != nil {
return err
}
}
@ -480,13 +482,13 @@ func (s *Server) startSingleMode() error {
if err != nil {
logging.Error().Msg("Failed to create pprof handler: " + err.Error())
} else {
if err := s.locationEngine.AddExact(pprofHandler.Path(), pprofHandler.ServeHTTP, false); err != nil {
if err := s.handleRegistrationError("pprof", pprofHandler.Path(), err); err != nil {
if regErr := s.locationEngine.AddExact(pprofHandler.Path(), pprofHandler.ServeHTTP, false); regErr != nil {
if err := s.handleRegistrationError("pprof", pprofHandler.Path(), regErr); err != nil {
return err
}
}
if err := s.locationEngine.AddPrefixPriority(pprofHandler.Path()+"/", pprofHandler.ServeHTTP, false); err != nil {
if err := s.handleRegistrationError("pprof", pprofHandler.Path()+"/", err); err != nil {
if regErr := s.locationEngine.AddPrefixPriority(pprofHandler.Path()+"/", pprofHandler.ServeHTTP, false); regErr != nil {
if err := s.handleRegistrationError("pprof", pprofHandler.Path()+"/", regErr); err != nil {
return err
}
}
@ -498,8 +500,8 @@ func (s *Server) startSingleMode() error {
if err != nil {
logging.Error().Msg("Failed to create cache purge handler: " + err.Error())
} else {
if err := s.locationEngine.AddExact(purgeHandler.Path(), purgeHandler.ServeHTTP, false); err != nil {
if err := s.handleRegistrationError("cache-purge", purgeHandler.Path(), err); err != nil {
if regErr := s.locationEngine.AddExact(purgeHandler.Path(), purgeHandler.ServeHTTP, false); regErr != nil {
if err := s.handleRegistrationError("cache-purge", purgeHandler.Path(), regErr); err != nil {
return err
}
}
@ -650,7 +652,7 @@ func (s *Server) startMultiServerMode() error {
serverCfg := &s.config.Servers[i]
ln, err := s.createListener(serverCfg)
if err != nil {
for j := 0; j < i; j++ {
for j := range i {
if s.listeners[j] != nil {
_ = s.listeners[j].Close()
}

View File

@ -136,7 +136,7 @@ func (l *leastConn) Select(targets []*Target) *Target {
if !t.healthy.Load() {
continue
}
conns := atomic.LoadInt64(&t.conns)
conns := t.conns.Load()
if selected == nil || conns < minConns {
selected = t
minConns = conns
@ -293,7 +293,7 @@ type Server struct {
// upstreams 上游配置映射
upstreams map[string]*Upstream
// connCount 当前连接数
connCount int64
connCount atomic.Int64
// mu 读写锁,保护并发访问
mu sync.RWMutex
// running 运行状态标志
@ -329,7 +329,7 @@ type Target struct {
// healthy 健康状态
healthy atomic.Bool
// conns 当前连接数
conns int64
conns atomic.Int64
}
// HealthChecker Stream 健康检查器。
@ -528,7 +528,7 @@ func (s *Server) acceptLoop(addr string, listener net.Listener) {
continue
}
atomic.AddInt64(&s.connCount, 1)
s.connCount.Add(1)
go s.handleConnection(conn, addr)
}
}
@ -547,7 +547,7 @@ func (s *Server) acceptLoop(addr string, listener net.Listener) {
func (s *Server) handleConnection(clientConn net.Conn, _ string) {
defer func() {
_ = clientConn.Close()
atomic.AddInt64(&s.connCount, -1)
s.connCount.Add(-1)
}()
s.mu.RLock()
@ -569,8 +569,8 @@ func (s *Server) handleConnection(clientConn net.Conn, _ string) {
return // 无可用目标
}
atomic.AddInt64(&target.conns, 1)
defer func() { atomic.AddInt64(&target.conns, -1) }()
target.conns.Add(1)
defer func() { target.conns.Add(-1) }()
// 连接目标
targetConn, err := net.DialTimeout("tcp", target.addr, 10*time.Second)
@ -808,7 +808,7 @@ func (s *udpServer) getOrCreateSession(clientAddr *net.UDPAddr) (*udpSession, er
return nil, err
}
atomic.AddInt64(&target.conns, 1)
target.conns.Add(1)
// 创建新会话
session = &udpSession{
@ -855,7 +855,7 @@ func (sess *udpSession) close() {
_ = sess.targetConn.Close()
}
if sess.target != nil {
atomic.AddInt64(&sess.target.conns, -1)
sess.target.conns.Add(-1)
}
})
}

View File

@ -260,8 +260,8 @@ func BenchmarkStreamBalancerSelect(b *testing.B) {
targets[i] = &Target{
addr: fmt.Sprintf("backend%d:8080", i),
weight: i + 1,
conns: int64(i * 10), // 模拟不同连接数
}
targets[i].conns.Store(int64(i * 10))
targets[i].healthy.Store(true)
}
@ -353,8 +353,8 @@ func BenchmarkStreamLeastConnWithVaryingConns(b *testing.B) {
targets[i] = &Target{
addr: fmt.Sprintf("backend%d:8080", i),
weight: 1,
conns: conns,
}
targets[i].conns.Store(conns)
targets[i].healthy.Store(true)
}

View File

@ -13,7 +13,6 @@ package stream
import (
"net"
"sync"
"sync/atomic"
"testing"
"time"
)
@ -96,10 +95,13 @@ func TestRoundRobinBalancer(t *testing.T) {
func TestLeastConnBalancer(t *testing.T) {
targets := []*Target{
{addr: "localhost:8001", conns: 5},
{addr: "localhost:8002", conns: 2},
{addr: "localhost:8003", conns: 8},
{addr: "localhost:8001"},
{addr: "localhost:8002"},
{addr: "localhost:8003"},
}
targets[0].conns.Store(5)
targets[1].conns.Store(2)
targets[2].conns.Store(8)
for _, t := range targets {
t.healthy.Store(true)
}
@ -249,12 +251,12 @@ func TestConcurrentConnections(t *testing.T) {
var wg sync.WaitGroup
for range 100 {
wg.Go(func() {
atomic.AddInt64(&s.connCount, 1)
s.connCount.Add(1)
})
}
wg.Wait()
if s.connCount != 100 {
if s.connCount.Load() != 100 {
t.Errorf("Expected 100 connections, got %d", s.connCount)
}
}
@ -335,10 +337,13 @@ func TestRoundRobinBalancerWithSingleTarget(t *testing.T) {
func TestLeastConnBalancerWithTie(t *testing.T) {
lc := newLeastConn()
targets := []*Target{
{addr: "backend1:8080", conns: 5},
{addr: "backend2:8080", conns: 5},
{addr: "backend3:8080", conns: 5},
{addr: "backend1:8080"},
{addr: "backend2:8080"},
{addr: "backend3:8080"},
}
targets[0].conns.Store(5)
targets[1].conns.Store(5)
targets[2].conns.Store(5)
for _, t := range targets {
t.healthy.Store(true)
}