package main import ( "fmt" "sync" "time" ) // Debouncer receives events and sends a debounced event after a quiet period. // It ensures that if events come rapidly, only the last one (after a pause) // triggers the final action. func Debouncer(input <-chan string, delay time.Duration) <-chan string { output := make(chan string) go func() { var timer *time.Timer var lastEvent string for { select { case event, ok := <-input: if !ok { // Input channel closed, drain any pending event and exit if timer != nil { timer.Stop() } if lastEvent != "" { output <- lastEvent } close(output) return } lastEvent = event if timer != nil { timer.Stop() } timer = time.AfterFunc(delay, func() { output <- lastEvent lastEvent = "" // Reset after sending }) case <-time.After(5 * time.Minute): // Prevent goroutine leak if no events for long time (optional) // This case is a safeguard. In a real app, you might want a context for shutdown. // For a debouncer, it's often expected to run indefinitely or be managed by its caller's context. return // Exit if no events for a very long time } } }() return output } func main() { inputEvents := make(chan string) debouncedOutput := Debouncer(inputEvents, 100*time.Millisecond) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for event := range debouncedOutput { fmt.Printf("Debounced event received: %s at %s ", event, time.Now().Format("15:04:05.000")) } fmt.Println("Debounced output channel closed.") }() fmt.Println("Sending events rapidly...") inputEvents <- "event-A" time.Sleep(20 * time.Millisecond) inputEvents <- "event-B" time.Sleep(30 * time.Millisecond) inputEvents <- "event-C" time.Sleep(150 * time.Millisecond) // This one should pass through fmt.Println("Sending another burst...") inputEvents <- "event-D" time.Sleep(10 * time.Millisecond) inputEvents <- "event-E" time.Sleep(10 * time.Millisecond) inputEvents <- "event-F" time.Sleep(150 * time.Millisecond) // This one should pass through fmt.Println("Closing input channel.") close(inputEvents) wg.Wait() fmt.Println("Main finished.") }