ruby
41 lines · 5 steps
A thread-safe debouncer in Ruby
Collect rapid calls into one batch and flush them after a quiet period, using a mutex and a resettable timer thread.
Explained by
highlit
1class Debouncer
2 def initialize(delay:)
3 @delay = delay
4 @mutex = Mutex.new
5 @pending = []
6 @timer = nil
7 end
8
9 def call(item, &flush)
10 @mutex.synchronize do
11 @pending << item
12 @flush = flush
13 schedule
14 end
15 end
16
17 private
18
19 def schedule
20 @timer&.kill
21 @timer = Thread.new do
22 sleep @delay
23 flush_now
24 end
25 end
26
27 def flush_now
28 batch = nil
29 handler = nil
30 @mutex.synchronize do
31 return if @pending.empty?
32 batch = @pending
33 handler = @flush
34 @pending = []
35 @timer = nil
36 end
37 handler.call(batch)
38 rescue => e
39 warn "[Debouncer] flush failed: #{e.message}"
40 end
41end
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Debouncing coalesces bursts of events into a single delayed action by resetting a timer on every new call.
- 2A mutex guards shared state so concurrent callers and the timer thread never see a half-updated batch.
- 3Draining state under the lock and running the handler outside it keeps the critical section short and avoids holding the lock during slow work.
Related explainers
ruby
require "shellwords" require "open3" module Backup
Building safe shell commands in Ruby
shell-out
subprocess
command-injection
Intermediate
7 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
ruby
class LogAggregator BUCKET_FORMAT = "%Y-%m-%dT%H:%M" def initialize(entries)
Bucketing log entries by the minute in Ruby
aggregation
hashing
enumerable
Intermediate
5 steps
go
func (w *Watcher) resetDebounce(d time.Duration) { if !w.timer.Stop() { select { case <-w.timer.C:
Debouncing a stream of events in Go
debounce
timers
channels
Advanced
7 steps
ruby
class WeeklySignupsReport DEFAULT_WEEKS = 12 def initialize(weeks: DEFAULT_WEEKS, source: User.all)
Building a weekly signups report in Rails
service object
aggregation
group by
Intermediate
7 steps
ruby
class ApplicationController < ActionController::Base EXPERIMENTS = { checkout_button_color: %w[control blue green], onboarding_flow: %w[control streamlined]
How A/B test cohorts are assigned in Rails
a-b-testing
cookies
hashing
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-thread-safe-debouncer-in-ruby-explained-ruby-2d18/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.