fix(n+1): 批量查询替代循环单查
- IsAdminBootstrapRequired: userRepo.GetByID 循环 → GetByIDs 批量 - AssignRoles: roleRepo.GetByID 循环 → GetByIDs 批量 - 在 userRepositoryInterface 补充 GetByIDs 方法签名
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user