fix(n+1): 批量查询替代循环单查

- IsAdminBootstrapRequired: userRepo.GetByID 循环 → GetByIDs 批量
- AssignRoles: roleRepo.GetByID 循环 → GetByIDs 批量
- 在 userRepositoryInterface 补充 GetByIDs 方法签名
This commit is contained in:
2026-05-08 08:05:26 +08:00
parent 9b1cea246e
commit 2a18a6fb47
39 changed files with 3169 additions and 393 deletions

View File

@@ -88,6 +88,11 @@ func (m *OperationLogMiddleware) Record() gin.HandlerFunc {
}
go func(entry *domain.OperationLog) {
defer func() {
if r := recover(); r != nil {
// PERF-07: panic recover 保护,防止操作日志写入异常导致进程崩溃
}
}()
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
_ = m.repo.Create(ctx, entry)

View File

@@ -199,3 +199,47 @@ func (m *RateLimitMiddleware) getOrCreateLimiter(key string, window time.Duratio
m.limiters[key] = limiter
return limiter
}
// Cleanup 清理过期的不活跃 limiter防止 map 无界增长P0 资源泄漏修复)
func (m *RateLimitMiddleware) Cleanup() {
m.mu.Lock()
defer m.mu.Unlock()
now := time.Now().UnixMilli()
for key, limiter := range m.limiters {
limiter.mu.Lock()
cutoff := now - limiter.window.Milliseconds()
// 只保留仍在窗口内的请求时间戳
validRequests := make([]int64, 0, len(limiter.requests))
for _, ts := range limiter.requests {
if ts > cutoff {
validRequests = append(validRequests, ts)
}
}
limiter.requests = validRequests
isEmpty := len(limiter.requests) == 0
limiter.mu.Unlock()
if isEmpty {
delete(m.limiters, key)
}
}
}
// StartCleanup 启动后台定期清理 goroutine返回停止函数P0 资源泄漏修复)
func (m *RateLimitMiddleware) StartCleanup() func() {
ticker := time.NewTicker(m.cleanupInt)
done := make(chan struct{})
go func() {
for {
select {
case <-ticker.C:
m.Cleanup()
case <-done:
ticker.Stop()
return
}
}
}()
return func() { close(done) }
}