package ingestion import ( "sync" "time" ) type Batcher[T any] struct { mu sync.Mutex items []T size int timeout time.Duration createdAt time.Time } func NewBatcher[T any](size int, timeout time.Duration) *Batcher[T] { return &Batcher[T]{ items: make([]T, 0, size), size: size, timeout: timeout, createdAt: time.Now(), } } func (b *Batcher[T]) Add(item T) { b.mu.Lock() defer b.mu.Unlock() if len(b.items) == 0 { b.createdAt = time.Now() } b.items = append(b.items, item) } func (b *Batcher[T]) IsFull() bool { b.mu.Lock() defer b.mu.Unlock() return len(b.items) >= b.size } func (b *Batcher[T]) IsExpired() bool { b.mu.Lock() defer b.mu.Unlock() if len(b.items) == 0 { return false } return time.Since(b.createdAt) >= b.timeout } func (b *Batcher[T]) Get() []T { b.mu.Lock() defer b.mu.Unlock() items := make([]T, len(b.items)) copy(items, b.items) return items } func (b *Batcher[T]) Clear() { b.mu.Lock() defer b.mu.Unlock() b.items = b.items[:0] }