fix(server): use atomic.Bool for Server.running to eliminate data race
Server.running was a plain bool accessed from multiple goroutines (start/stop/signal handlers). Convert to atomic.Bool with Store/Load to make all accesses safe for concurrent use. Updates all test files to use the new atomic API.
This commit is contained in:
parent
0359d4c477
commit
ac66ea5534
@ -136,7 +136,7 @@ func (s *Server) StopWithTimeout(timeout time.Duration) error {
|
|||||||
timeout = 5 * time.Second
|
timeout = 5 * time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
s.running = false
|
s.running.Store(false)
|
||||||
s.cleanupResources()
|
s.cleanupResources()
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
@ -180,7 +180,7 @@ func (s *Server) StopWithTimeout(timeout time.Duration) error {
|
|||||||
// - 推荐在生产环境使用此方法关闭服务器
|
// - 推荐在生产环境使用此方法关闭服务器
|
||||||
// - 超时后会强制关闭,可能导致部分请求中断
|
// - 超时后会强制关闭,可能导致部分请求中断
|
||||||
func (s *Server) GracefulStop(timeout time.Duration) error {
|
func (s *Server) GracefulStop(timeout time.Duration) error {
|
||||||
s.running = false
|
s.running.Store(false)
|
||||||
s.cleanupResources()
|
s.cleanupResources()
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
|||||||
@ -79,7 +79,7 @@ type Server struct {
|
|||||||
requests atomic.Int64
|
requests atomic.Int64
|
||||||
bytesSent atomic.Int64
|
bytesSent atomic.Int64
|
||||||
bytesReceived atomic.Int64
|
bytesReceived atomic.Int64
|
||||||
running bool
|
running atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New 创建 HTTP 服务器实例。
|
// New 创建 HTTP 服务器实例。
|
||||||
@ -450,7 +450,7 @@ func (s *Server) startSingleMode() error {
|
|||||||
|
|
||||||
s.fastServer = s.createFastServer(serverCfg, s.handler)
|
s.fastServer = s.createFastServer(serverCfg, s.handler)
|
||||||
|
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建监听器并保存,用于热升级
|
// 创建监听器并保存,用于热升级
|
||||||
ln, err := s.createListener(serverCfg)
|
ln, err := s.createListener(serverCfg)
|
||||||
@ -580,7 +580,7 @@ func (s *Server) startVHostMode() error {
|
|||||||
|
|
||||||
s.fastServer = s.createFastServer(serverCfg, s.handler)
|
s.fastServer = s.createFastServer(serverCfg, s.handler)
|
||||||
|
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建监听器并保存,用于热升级
|
// 创建监听器并保存,用于热升级
|
||||||
ln, err := s.createListener(serverCfg)
|
ln, err := s.createListener(serverCfg)
|
||||||
@ -739,7 +739,7 @@ func (s *Server) startMultiServerMode() error {
|
|||||||
return firstErr
|
return firstErr
|
||||||
}
|
}
|
||||||
|
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 启动所有服务器
|
// 启动所有服务器
|
||||||
for idx, fastSrv := range s.fastServers {
|
for idx, fastSrv := range s.fastServers {
|
||||||
|
|||||||
@ -55,7 +55,7 @@ func TestNew(t *testing.T) {
|
|||||||
t.Error("Server.config not set correctly")
|
t.Error("Server.config not set correctly")
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.running {
|
if s.running.Load() {
|
||||||
t.Error("Server.running should be false initially")
|
t.Error("Server.running should be false initially")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,7 +545,7 @@ func TestServer_Running(t *testing.T) {
|
|||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
|
|
||||||
// 初始状态应为未运行
|
// 初始状态应为未运行
|
||||||
if s.running {
|
if s.running.Load() {
|
||||||
t.Error("Initial running state should be false")
|
t.Error("Initial running state should be false")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1140,7 +1140,7 @@ func TestServer_StopWithTimeout_WithFastServer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建 mock fastServer
|
// 创建 mock fastServer
|
||||||
s.fastServer = &fasthttp.Server{}
|
s.fastServer = &fasthttp.Server{}
|
||||||
@ -1295,7 +1295,7 @@ func TestServer_GracefulStop_WithFastServers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建多个 fastServer
|
// 创建多个 fastServer
|
||||||
s.fastServers = []*fasthttp.Server{
|
s.fastServers = []*fasthttp.Server{
|
||||||
@ -1319,7 +1319,7 @@ func TestServer_StopWithTimeout_WithFastServers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建多个 fastServer
|
// 创建多个 fastServer
|
||||||
s.fastServers = []*fasthttp.Server{
|
s.fastServers = []*fasthttp.Server{
|
||||||
@ -1641,9 +1641,9 @@ func TestGracefulStop_RunningState(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
if !s.running {
|
if !s.running.Load() {
|
||||||
t.Fatal("running should be true before GracefulStop")
|
t.Fatal("running should be true before GracefulStop")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1652,7 +1652,7 @@ func TestGracefulStop_RunningState(t *testing.T) {
|
|||||||
t.Errorf("GracefulStop failed: %v", err)
|
t.Errorf("GracefulStop failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.running {
|
if s.running.Load() {
|
||||||
t.Error("running should be false after GracefulStop")
|
t.Error("running should be false after GracefulStop")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1674,7 +1674,7 @@ func TestGracefulStop_WithPool(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 初始化并启动 pool
|
// 初始化并启动 pool
|
||||||
s.pool = initGoroutinePool(&cfg.Performance)
|
s.pool = initGoroutinePool(&cfg.Performance)
|
||||||
@ -1697,7 +1697,7 @@ func TestGracefulStop_WithHealthCheckers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建 mock healthChecker (使用 nil,因为我们只测试循环不会 panic)
|
// 创建 mock healthChecker (使用 nil,因为我们只测试循环不会 panic)
|
||||||
s.healthCheckers = nil
|
s.healthCheckers = nil
|
||||||
@ -1717,7 +1717,7 @@ func TestGracefulStop_WithAccessLog(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建 accessLogMiddleware
|
// 创建 accessLogMiddleware
|
||||||
s.accessLogMiddleware = accesslog.New(&config.LoggingConfig{})
|
s.accessLogMiddleware = accesslog.New(&config.LoggingConfig{})
|
||||||
@ -1737,7 +1737,7 @@ func TestGracefulStop_WithTLSManager(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建临时证书文件
|
// 创建临时证书文件
|
||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
@ -1773,7 +1773,7 @@ func TestGracefulStop_WithLuaEngine(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建 Lua 引擎
|
// 创建 Lua 引擎
|
||||||
luaEngine, err := lua.NewEngine(lua.DefaultConfig())
|
luaEngine, err := lua.NewEngine(lua.DefaultConfig())
|
||||||
@ -1801,7 +1801,7 @@ func TestGracefulStop_Timeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建一个真实的 fastServer,但通过模拟长时间关闭来测试超时
|
// 创建一个真实的 fastServer,但通过模拟长时间关闭来测试超时
|
||||||
s.fastServer = &fasthttp.Server{
|
s.fastServer = &fasthttp.Server{
|
||||||
@ -1834,7 +1834,7 @@ func TestGracefulStop_AllComponents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 初始化所有组件
|
// 初始化所有组件
|
||||||
s.pool = initGoroutinePool(&cfg.Performance)
|
s.pool = initGoroutinePool(&cfg.Performance)
|
||||||
@ -1856,7 +1856,7 @@ func TestGracefulStop_AllComponents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证 running 状态
|
// 验证 running 状态
|
||||||
if s.running {
|
if s.running.Load() {
|
||||||
t.Error("running should be false after GracefulStop")
|
t.Error("running should be false after GracefulStop")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1881,7 +1881,7 @@ func TestGracefulStop_WithAccessControl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建 AccessControl
|
// 创建 AccessControl
|
||||||
ac, err := security.NewAccessControl(&cfg.Servers[0].Security.Access)
|
ac, err := security.NewAccessControl(&cfg.Servers[0].Security.Access)
|
||||||
@ -1909,7 +1909,7 @@ func TestGracefulStop_ContextCancelled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建一个监听中的服务器
|
// 创建一个监听中的服务器
|
||||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
@ -1951,7 +1951,7 @@ func TestGracefulStop_MultipleHealthCheckers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建多个 mock healthChecker
|
// 创建多个 mock healthChecker
|
||||||
// 注意:这里使用 nil slice 测试空循环不会 panic
|
// 注意:这里使用 nil slice 测试空循环不会 panic
|
||||||
@ -1972,7 +1972,7 @@ func TestGracefulStop_NilComponents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 确保所有组件为 nil
|
// 确保所有组件为 nil
|
||||||
s.pool = nil
|
s.pool = nil
|
||||||
@ -1989,7 +1989,7 @@ func TestGracefulStop_NilComponents(t *testing.T) {
|
|||||||
t.Errorf("GracefulStop failed: %v", err)
|
t.Errorf("GracefulStop failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.running {
|
if s.running.Load() {
|
||||||
t.Error("running should be false after GracefulStop")
|
t.Error("running should be false after GracefulStop")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2003,7 +2003,7 @@ func TestGracefulStop_FastServersWithNil(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
|
|
||||||
// 创建包含 nil 的 fastServers
|
// 创建包含 nil 的 fastServers
|
||||||
s.fastServers = []*fasthttp.Server{nil, {}, nil}
|
s.fastServers = []*fasthttp.Server{nil, {}, nil}
|
||||||
@ -2023,7 +2023,7 @@ func TestGracefulStop_ZeroTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
s.fastServer = &fasthttp.Server{}
|
s.fastServer = &fasthttp.Server{}
|
||||||
|
|
||||||
err := s.GracefulStop(0)
|
err := s.GracefulStop(0)
|
||||||
@ -2042,7 +2042,7 @@ func TestGracefulStop_NegativeTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s := New(cfg)
|
s := New(cfg)
|
||||||
s.running = true
|
s.running.Store(true)
|
||||||
s.fastServer = &fasthttp.Server{}
|
s.fastServer = &fasthttp.Server{}
|
||||||
|
|
||||||
err := s.GracefulStop(-1 * time.Second)
|
err := s.GracefulStop(-1 * time.Second)
|
||||||
|
|||||||
@ -65,7 +65,7 @@ func TestStart_Integration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 测试初始状态
|
// 测试初始状态
|
||||||
if s.running {
|
if s.running.Load() {
|
||||||
t.Error("Server should not be running initially")
|
t.Error("Server should not be running initially")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user