Debounce Rapid Function Calls

Coalesce bursts of events into one delayed function call using time.AfterFunc and a mutex-protected timer per debouncer.

GoResilience

Code

snippet
package main

import (
	"fmt"
	"sync"
	"time"
)

type Debouncer struct {
	mu    sync.Mutex
	delay time.Duration
	timer *time.Timer
}

func NewDebouncer(delay time.Duration) *Debouncer {
	return &Debouncer{delay: delay}
}

func (d *Debouncer) Do(fn func()) {
	d.mu.Lock()
	defer d.mu.Unlock()
	if d.timer != nil {
		d.timer.Stop()
	}
	d.timer = time.AfterFunc(d.delay, fn)
}

func (d *Debouncer) Stop() {
	d.mu.Lock()
	defer d.mu.Unlock()
	if d.timer != nil {
		d.timer.Stop()
	}
}

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	debounce := NewDebouncer(50 * time.Millisecond)
	start := time.Now()
	for index := 0; index < 5; index++ {
		debounce.Do(func() {
			fmt.Println("fired after", time.Since(start).Round(time.Millisecond))
			wg.Done()
		})
		time.Sleep(10 * time.Millisecond)
	}
	wg.Wait()
}