安全问题修复: - X-Forwarded-For越界检查(auth.go) - checkTokenStatus Context参数传递(auth.go) - Type Assertion安全检查(auth.go) 性能问题修复: - TokenCache过期清理机制 - BruteForceProtection过期清理 - InMemoryIdempotencyStore过期清理 错误处理修复: - AuditStore.Emit返回error - domain层emitAudit辅助方法 - List方法返回空slice而非nil - 金额/价格负数验证 架构一致性: - 统一使用model.RoleHierarchyLevels 新增功能: - Alert API完整实现(CRUD+Resolve) - pkg/error错误码集中管理
204 lines
4.1 KiB
Go
204 lines
4.1 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"sync"
|
||
"time"
|
||
|
||
"lijiaoqiao/supply-api/internal/audit/model"
|
||
)
|
||
|
||
// BatchBufferConfig 批量缓冲区配置
|
||
type BatchBufferConfig struct {
|
||
BatchSize int // 批量大小(默认50)
|
||
FlushInterval time.Duration // 刷新间隔(默认5ms)
|
||
BufferSize int // 通道缓冲大小(默认1000)
|
||
}
|
||
|
||
// DefaultBatchBufferConfig 默认配置
|
||
var DefaultBatchBufferConfig = BatchBufferConfig{
|
||
BatchSize: 50,
|
||
FlushInterval: 5 * time.Millisecond,
|
||
BufferSize: 1000,
|
||
}
|
||
|
||
// BatchBuffer 批量写入缓冲区
|
||
// 设计目标:50条/批或5ms刷新间隔,支持5K-8K TPS
|
||
type BatchBuffer struct {
|
||
config BatchBufferConfig
|
||
eventCh chan *model.AuditEvent
|
||
buffer []*model.AuditEvent
|
||
mu sync.Mutex
|
||
closed bool
|
||
|
||
flushTick *time.Ticker
|
||
stopCh chan struct{}
|
||
doneCh chan struct{}
|
||
|
||
// FlushHandler 处理批量刷新回调
|
||
FlushHandler func(events []*model.AuditEvent) error
|
||
}
|
||
|
||
// NewBatchBuffer 创建批量缓冲区
|
||
func NewBatchBuffer(batchSize int, flushInterval time.Duration) *BatchBuffer {
|
||
config := DefaultBatchBufferConfig
|
||
if batchSize > 0 {
|
||
config.BatchSize = batchSize
|
||
}
|
||
if flushInterval > 0 {
|
||
config.FlushInterval = flushInterval
|
||
}
|
||
|
||
return &BatchBuffer{
|
||
config: config,
|
||
eventCh: make(chan *model.AuditEvent, config.BufferSize),
|
||
buffer: make([]*model.AuditEvent, 0, batchSize),
|
||
flushTick: time.NewTicker(config.FlushInterval),
|
||
stopCh: make(chan struct{}),
|
||
doneCh: make(chan struct{}),
|
||
}
|
||
}
|
||
|
||
// Start 启动批量缓冲处理
|
||
func (b *BatchBuffer) Start(ctx context.Context) error {
|
||
go b.run()
|
||
return nil
|
||
}
|
||
|
||
// run 后台处理循环
|
||
func (b *BatchBuffer) run() {
|
||
defer close(b.doneCh)
|
||
|
||
for {
|
||
select {
|
||
case <-b.stopCh:
|
||
// 停止信号:处理剩余缓冲
|
||
b.flush()
|
||
return
|
||
case event := <-b.eventCh:
|
||
b.addEvent(event)
|
||
case <-b.flushTick.C:
|
||
b.flush()
|
||
}
|
||
}
|
||
}
|
||
|
||
// addEvent 添加事件到缓冲
|
||
func (b *BatchBuffer) addEvent(event *model.AuditEvent) {
|
||
b.mu.Lock()
|
||
defer b.mu.Unlock()
|
||
|
||
b.buffer = append(b.buffer, event)
|
||
|
||
// 达到批量大小立即刷新
|
||
if len(b.buffer) >= b.config.BatchSize {
|
||
b.doFlushLocked()
|
||
}
|
||
}
|
||
|
||
// flush 刷新缓冲(带锁)- 也会处理eventCh中的待处理事件
|
||
func (b *BatchBuffer) flush() {
|
||
b.mu.Lock()
|
||
defer b.mu.Unlock()
|
||
|
||
// 处理eventCh中已有的事件
|
||
for {
|
||
select {
|
||
case event := <-b.eventCh:
|
||
b.buffer = append(b.buffer, event)
|
||
default:
|
||
goto done
|
||
}
|
||
}
|
||
done:
|
||
b.doFlushLocked()
|
||
}
|
||
|
||
// doFlushLocked 执行刷新( caller 必须持锁)
|
||
func (b *BatchBuffer) doFlushLocked() {
|
||
if len(b.buffer) == 0 {
|
||
return
|
||
}
|
||
|
||
// 复制缓冲数据
|
||
events := make([]*model.AuditEvent, len(b.buffer))
|
||
copy(events, b.buffer)
|
||
|
||
// 清空缓冲
|
||
b.buffer = b.buffer[:0]
|
||
|
||
// 调用处理函数(如果已设置)
|
||
if b.FlushHandler != nil {
|
||
if err := b.FlushHandler(events); err != nil {
|
||
// TODO: 错误处理 - 记录日志、重试等
|
||
// 当前简化处理:仅记录
|
||
}
|
||
}
|
||
}
|
||
|
||
// Add 添加审计事件
|
||
func (b *BatchBuffer) Add(event *model.AuditEvent) error {
|
||
b.mu.Lock()
|
||
defer b.mu.Unlock()
|
||
|
||
if b.closed {
|
||
return ErrBufferClosed
|
||
}
|
||
|
||
select {
|
||
case b.eventCh <- event:
|
||
return nil
|
||
default:
|
||
// 通道满,添加到缓冲
|
||
b.buffer = append(b.buffer, event)
|
||
if len(b.buffer) >= b.config.BatchSize {
|
||
b.doFlushLocked()
|
||
}
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// FlushNow 立即刷新
|
||
func (b *BatchBuffer) FlushNow() error {
|
||
b.flush()
|
||
return nil
|
||
}
|
||
|
||
// Close 关闭缓冲区
|
||
func (b *BatchBuffer) Close() error {
|
||
b.mu.Lock()
|
||
if b.closed {
|
||
b.mu.Unlock()
|
||
return nil
|
||
}
|
||
b.closed = true
|
||
b.mu.Unlock()
|
||
|
||
close(b.stopCh)
|
||
<-b.doneCh
|
||
b.flushTick.Stop()
|
||
close(b.eventCh)
|
||
|
||
return nil
|
||
}
|
||
|
||
// SetFlushHandler 设置刷新处理器
|
||
func (b *BatchBuffer) SetFlushHandler(handler func(events []*model.AuditEvent) error) {
|
||
b.FlushHandler = handler
|
||
}
|
||
|
||
// 错误定义
|
||
var (
|
||
ErrBufferClosed = &BatchBufferError{"buffer is closed"}
|
||
ErrMissingFlushHandler = &BatchBufferError{"flush handler not set"}
|
||
)
|
||
|
||
// BatchBufferError 批量缓冲错误
|
||
type BatchBufferError struct {
|
||
msg string
|
||
}
|
||
|
||
func (e *BatchBufferError) Error() string {
|
||
return e.msg
|
||
}
|