package queue import ( "sync" "time" "github.com/pkg/errors" ) type DebouncerMap struct { debouncers sync.Map } func NewDebouncerMap() *DebouncerMap { return &DebouncerMap{ debouncers: sync.Map{}, } } func (m *DebouncerMap) Do(key string, after time.Duration, fn func()) { newDebouncer := NewDebouncer(after) rawDebouncer, loaded := m.debouncers.LoadOrStore(key, newDebouncer) debouncer, ok := rawDebouncer.(*Debouncer) if !ok { panic(errors.Errorf("unexpected debouncer value, expected '%T', got '%T'", newDebouncer, rawDebouncer)) } if loaded { debouncer.Update(after) } debouncer.Do(fn) } func NewDebouncer(after time.Duration) *Debouncer { return &Debouncer{after: after} } type Debouncer struct { mu sync.Mutex after time.Duration timer *time.Timer fn func() } func (d *Debouncer) Do(fn func()) { d.mu.Lock() defer d.mu.Unlock() if d.timer != nil { d.timer.Stop() } d.fn = fn d.timer = time.AfterFunc(d.after, d.fn) } func (d *Debouncer) Update(after time.Duration) { d.mu.Lock() defer d.mu.Unlock() if after == d.after { return } if d.timer != nil { d.timer.Stop() } d.after = after d.timer = time.AfterFunc(d.after, d.fn) }