85 lines
2.3 KiB
Go
85 lines
2.3 KiB
Go
package service
|
||
|
||
import (
|
||
"sync"
|
||
"time"
|
||
|
||
"hyapp/pkg/appcode"
|
||
"hyapp/services/room-service/internal/room/outbox"
|
||
)
|
||
|
||
const (
|
||
// robotOutboxSampleWindow 是 v1 展示降采样窗口:同房间同事件类型 2 秒内只保留一条 robot outbox。
|
||
robotOutboxSampleWindow = 2 * time.Second
|
||
)
|
||
|
||
type robotOutboxSampleKey struct {
|
||
appCode string
|
||
roomID string
|
||
eventType string
|
||
}
|
||
|
||
type robotOutboxSampler struct {
|
||
mu sync.Mutex
|
||
lastWindow map[robotOutboxSampleKey]int64
|
||
}
|
||
|
||
func newRobotOutboxSampler() *robotOutboxSampler {
|
||
return &robotOutboxSampler{lastWindow: make(map[robotOutboxSampleKey]int64)}
|
||
}
|
||
|
||
func (s *Service) sampleRobotOutboxRecords(records []outbox.Record) []outbox.Record {
|
||
if len(records) == 0 || s == nil || s.robotOutboxSampler == nil {
|
||
return records
|
||
}
|
||
return s.robotOutboxSampler.filter(records, robotOutboxSampleWindow)
|
||
}
|
||
|
||
func (s *robotOutboxSampler) filter(records []outbox.Record, window time.Duration) []outbox.Record {
|
||
if s == nil || window <= 0 || len(records) == 0 {
|
||
return records
|
||
}
|
||
|
||
windowMS := window.Milliseconds()
|
||
out := make([]outbox.Record, 0, len(records))
|
||
s.mu.Lock()
|
||
defer s.mu.Unlock()
|
||
|
||
var newestWindow int64
|
||
for _, record := range records {
|
||
key := robotOutboxSampleKey{
|
||
appCode: appcode.Normalize(record.AppCode),
|
||
roomID: record.RoomID,
|
||
eventType: record.EventType,
|
||
}
|
||
createdAtMS := record.CreatedAtMS
|
||
if createdAtMS <= 0 && record.Envelope != nil {
|
||
createdAtMS = record.Envelope.GetOccurredAtMs()
|
||
}
|
||
windowStartMS := createdAtMS / windowMS * windowMS
|
||
if windowStartMS > newestWindow {
|
||
newestWindow = windowStartMS
|
||
}
|
||
if last, exists := s.lastWindow[key]; exists && windowStartMS <= last {
|
||
// 展示事件过密时只丢 robot outbox 记录;Room Cell 命令、房间热度、榜单和火箭状态已经在进入这里前完成计算。
|
||
continue
|
||
}
|
||
s.lastWindow[key] = windowStartMS
|
||
out = append(out, record)
|
||
}
|
||
|
||
if newestWindow > 0 && len(s.lastWindow) > 1024 {
|
||
// 机器人房数量和事件类型有限,超过阈值说明进程运行很久;保留最近几个窗口即可避免 map 常驻增长。
|
||
s.pruneLocked(newestWindow - 4*windowMS)
|
||
}
|
||
return out
|
||
}
|
||
|
||
func (s *robotOutboxSampler) pruneLocked(beforeWindowMS int64) {
|
||
for key, windowStartMS := range s.lastWindow {
|
||
if windowStartMS < beforeWindowMS {
|
||
delete(s.lastWindow, key)
|
||
}
|
||
}
|
||
}
|