Files
wehub-resource-sync bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:22:54 +08:00

72 lines
1.3 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package event
import (
"sync"
"time"
)
const (
defaultDedupTTL = 5 * time.Minute
defaultRingSize = 10000
)
// DedupFilter: seen map is sole authority; ring only bounds map size via overflow eviction.
type DedupFilter struct {
seen map[string]time.Time
ring []string
pos int
ttl time.Duration
mu sync.Mutex
}
func NewDedupFilter() *DedupFilter {
return NewDedupFilterWithSize(defaultRingSize, defaultDedupTTL)
}
func NewDedupFilterWithSize(ringSize int, ttl time.Duration) *DedupFilter {
return &DedupFilter{
seen: make(map[string]time.Time),
ring: make([]string, ringSize),
ttl: ttl,
}
}
func (d *DedupFilter) IsDuplicate(eventID string) bool {
d.mu.Lock()
defer d.mu.Unlock()
now := time.Now()
if ts, ok := d.seen[eventID]; ok {
if now.Sub(ts) < d.ttl {
return true
}
delete(d.seen, eventID)
}
d.seen[eventID] = now
if old := d.ring[d.pos]; old != "" && old != eventID {
delete(d.seen, old)
}
d.ring[d.pos] = eventID
d.pos = (d.pos + 1) % len(d.ring)
if d.pos%1000 == 0 {
d.cleanupExpired(now)
}
return false
}
func (d *DedupFilter) cleanupExpired(now time.Time) {
for id, ts := range d.seen {
if now.Sub(ts) >= d.ttl {
delete(d.seen, id)
}
}
}