mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
全仓 race 扫描发现 upload/cache 监听器 DATA RACE:捕获 redis 客户端消除全局读竞争 + Stop 等待 done + 同型监听器(oauth×2/repository×2)加固
Result: {"status":"keep","total_issues":8,"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":92,"tsc_errors":0,"vitest_failed":0,"vitest_total":126}
This commit is contained in:
@@ -38,3 +38,23 @@
|
||||
frpc/frps 慢测试注入 backoff(为省 ~40s 改生产时序逻辑,不值)。
|
||||
- 未来如继续:可周期跑 `go test -race ./...` 全量(frpc/frps 慢套件);
|
||||
或前端 a11y 用 axe 做浏览器级审计(超出 eslint 静态规则)。
|
||||
|
||||
## 本会话新增(runs #39-#43)
|
||||
|
||||
已修复:
|
||||
- agent auth_cache negative 缓存无上限 → 10k 上限+过期清理(DoS 防护)
|
||||
- relay/flared 与 agent 三份重复 authenticateAccessToken → 共享 agent 版(负缓存共享,DB 压力下降)
|
||||
- websocket 三 hub:runWritePump 抽取、wsClientCore 嵌入(close/enqueue 单份)、broadcastAgent 合并
|
||||
- frps/frpc TOML 注入 → pkg/protocol/toml.go TOMLQuote 转义全部插值
|
||||
|
||||
评估后不修/暂缓:
|
||||
- cloudflare listMemberItems、config_version snapshot 证书循环的 N+1:管理端小 N 低频,
|
||||
加批量 repo API 属投机优化;若未来组员数量变大再做 ListZoneDomainsByIDs。
|
||||
- fatcontext ×3(oauth/upload/auth_source cache listener):别名赋值误报,非嵌套包装。
|
||||
- objectstore newOSSBackend/newWebDAVBackend 恒 nil error:跨后端工厂签名统一,刻意设计。
|
||||
- edge/updater assetNameForGOOSGOARCH 恒 "linux":跨平台预留参数,刻意泛化。
|
||||
- agent ResolverDirective explicitResolvers 原样插入 nginx conf:管理员配置属可信输入;
|
||||
若未来开放给低权限角色需加格式校验(IP 解析)。
|
||||
- pkg/render/openresty 管理端旋钮(ClientMaxBodySize 等)原样插值:管理员权限范围内。
|
||||
- frontend/settings/profile.tsx(858 行)超 AGENTS.md ~600 行指引:存量组件,拆分属
|
||||
纯重构无质量增益,暂缓;若后续要改该页面功能时顺手拆 components/。
|
||||
|
||||
@@ -41,3 +41,4 @@
|
||||
{"run":40,"commit":"0dd2cf9","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":77,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"websocket 三 hub 去重:抽 runWritePump 共享写泵 + 合并 agent 广播函数为 broadcastAgent","timestamp":1787708370650,"segment":0,"confidence":null,"asi":{"hypothesis":"三份 hub 的 writePump 完全重复(仅日志前缀不同),readPump 已有 runReadPump 抽取先例;BroadcastWAFIPGroups/BroadcastActiveConfig 复制粘贴","next_action_hint":"close() 3 份小重复可再合并但收益低;继续找其他模块的重复/无界增长","result":"metric 持平 8,全测试绿","refactor":"新增 websocket/write_pump.go runWritePump(对齐 runReadPump 模式),agent/relay/flared writePump 改委托;agent_hub 抽 broadcastAgent 合并两个广播函数"}}
|
||||
{"run":41,"commit":"efd8268","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":75,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"websocket 三 client 结构体去重:嵌入共享 wsClientCore(close/enqueue 单份实现)","timestamp":1787708975609,"segment":0,"confidence":null,"asi":{"hypothesis":"agentClient/relayClient/flaredClient 字段与 close/enqueue 完全相同,用组合(嵌入 wsClientCore)消除三份重复","next_action_hint":"代码库经 40 轮已高度收敛;后续可周期性跑 go test -race 全量","result":"metric 持平 8,全测试绿;净减 ~60 行重复代码","refactor":"新增 websocket/client_core.go:wsClientCore(nodeID/conn/send/done/once) + 共享 close/enqueue;三个 client 结构体改为嵌入"}}
|
||||
{"run":42,"commit":"ed1efd3","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":77,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"补 wsClientCore 并发测试 + close() 防 nil conn 守卫","timestamp":1787709222794,"segment":0,"confidence":null,"asi":{"hypothesis":"wsClientCore 并发语义(close 幂等、enqueue 不阻塞/关后拒绝)无测试覆盖","next_action_hint":"websocket 包已有基础并发测试;继续其他模块扫描","result":"metric 持平 8;测试还暴露 close 未防 nil conn 的防御缺口,已补守卫","refactor":"新增 websocket/client_core_test.go 3 个 -race 测试;client_core.go close() 增加 nil conn 守卫"}}
|
||||
{"run":43,"commit":"4f8e7e6","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":77,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"修复 frps/frpc TOML 配置注入:新增 protocol.TOMLQuote 并在两处配置渲染全部使用","timestamp":1787709693698,"segment":0,"confidence":null,"asi":{"hypothesis":"frps/frpc TOML 配置用裸 Fprintf 拼接,token/password/域名含引号、反斜杠、换行时会破坏配置或注入键","next_action_hint":"检查其他配置生成点是否有同类注入面(nginx/openresty 配置)","result":"metric 回到 8;frpc 慢套件 16.8s 全绿;mnd 曾短暂+1(Grow 魔法数),删除微优化后消除","security":"新增 pkg/protocol/toml.go TOMLQuote 转义助手 + toml_test.go;relay/frps renderConfig 与 flared/frpc buildFrpcToml 全部插值改为转义输出"}}
|
||||
|
||||
@@ -59,11 +59,12 @@ func startTokenCacheInvalidationListener() {
|
||||
tokenListenerCtx, tokenListenerCancel = context.WithCancel(context.Background())
|
||||
tokenListenerDone = make(chan struct{})
|
||||
|
||||
redisClient := db.Redis // 捕获当前客户端:goroutine 不读可变全局,避免与测试置空 db.Redis 竞争
|
||||
go func() {
|
||||
listenerCtx := tokenListenerCtx
|
||||
defer close(tokenListenerDone)
|
||||
|
||||
pubsub := db.Redis.Subscribe(listenerCtx, oauthTokenInvalidationChannel)
|
||||
pubsub := redisClient.Subscribe(listenerCtx, oauthTokenInvalidationChannel)
|
||||
defer func() {
|
||||
_ = pubsub.Close()
|
||||
}()
|
||||
@@ -102,11 +103,12 @@ func startUserCacheInvalidationListener() {
|
||||
userListenerCtx, userListenerCancel = context.WithCancel(context.Background())
|
||||
userListenerDone = make(chan struct{})
|
||||
|
||||
redisClient := db.Redis // 捕获当前客户端:goroutine 不读可变全局,避免与测试置空 db.Redis 竞争
|
||||
go func() {
|
||||
listenerCtx := userListenerCtx
|
||||
defer close(userListenerDone)
|
||||
|
||||
pubsub := db.Redis.Subscribe(listenerCtx, oauthUserInvalidationChannel)
|
||||
pubsub := redisClient.Subscribe(listenerCtx, oauthUserInvalidationChannel)
|
||||
defer func() {
|
||||
_ = pubsub.Close()
|
||||
}()
|
||||
|
||||
+10
-1
@@ -30,6 +30,7 @@ var (
|
||||
uploadMetaListenerOnce sync.Once
|
||||
uploadMetaListenerCtx context.Context
|
||||
uploadMetaListenerCancel context.CancelFunc
|
||||
uploadMetaListenerDone chan struct{}
|
||||
)
|
||||
|
||||
func uploadMetaRedisKey(id uint64) string {
|
||||
@@ -49,9 +50,13 @@ func ensureUploadMetaCacheListener() {
|
||||
|
||||
func startUploadMetaCacheInvalidationListener() {
|
||||
uploadMetaListenerCtx, uploadMetaListenerCancel = context.WithCancel(context.Background())
|
||||
uploadMetaListenerDone = make(chan struct{})
|
||||
// 捕获当前客户端:goroutine 不再读可变全局 db.Redis,测试置空/替换全局时不会数据竞争
|
||||
redisClient := db.Redis
|
||||
|
||||
go func() {
|
||||
pubsub := db.Redis.Subscribe(uploadMetaListenerCtx, uploadMetaInvalidationChan)
|
||||
defer close(uploadMetaListenerDone)
|
||||
pubsub := redisClient.Subscribe(uploadMetaListenerCtx, uploadMetaInvalidationChan)
|
||||
defer func() {
|
||||
_ = pubsub.Close()
|
||||
}()
|
||||
@@ -144,7 +149,11 @@ func ResetUploadMetaCacheForTest() {
|
||||
func StopUploadMetaCacheListener() {
|
||||
if uploadMetaListenerCancel != nil {
|
||||
uploadMetaListenerCancel()
|
||||
if uploadMetaListenerDone != nil {
|
||||
<-uploadMetaListenerDone // 等待 goroutine 退出,保证之后置空 db.Redis 不再竞争
|
||||
}
|
||||
uploadMetaListenerCancel = nil
|
||||
uploadMetaListenerDone = nil
|
||||
}
|
||||
uploadMetaListenerOnce = sync.Once{}
|
||||
}
|
||||
|
||||
@@ -119,11 +119,12 @@ func startAuthSourceCacheInvalidationListener() {
|
||||
authSourceListenerCtx, authSourceListenerCancel = context.WithCancel(context.Background())
|
||||
authSourceListenerDone = make(chan struct{})
|
||||
|
||||
redisClient := db.Redis // 捕获当前客户端:goroutine 不读可变全局,避免与测试置空 db.Redis 竞争
|
||||
go func() {
|
||||
listenerCtx := authSourceListenerCtx
|
||||
defer close(authSourceListenerDone)
|
||||
|
||||
pubsub := db.Redis.Subscribe(listenerCtx, authSourceInvalidationChannel)
|
||||
pubsub := redisClient.Subscribe(listenerCtx, authSourceInvalidationChannel)
|
||||
defer func() {
|
||||
_ = pubsub.Close()
|
||||
}()
|
||||
|
||||
@@ -105,11 +105,12 @@ func startSystemConfigCacheInvalidationListener() {
|
||||
systemConfigListenerCtx, systemConfigListenerCancel = context.WithCancel(context.Background())
|
||||
systemConfigListenerDone = make(chan struct{})
|
||||
|
||||
redisClient := db.Redis // 捕获当前客户端:goroutine 不读可变全局,避免与测试置空 db.Redis 竞争
|
||||
go func() {
|
||||
listenerCtx := systemConfigListenerCtx
|
||||
defer close(systemConfigListenerDone)
|
||||
|
||||
pubsub := db.Redis.Subscribe(listenerCtx, SystemConfigBroadcastChannel)
|
||||
pubsub := redisClient.Subscribe(listenerCtx, SystemConfigBroadcastChannel)
|
||||
defer func() {
|
||||
_ = pubsub.Close()
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user