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 "net/http" require "json" class UrlFetcher
A thread-pool URL fetcher in Ruby
concurrency
thread-pool
queues
Intermediate
8 steps
rust
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::thread;
A round-robin worker pool in Rust
concurrency
thread-pool
channels
Intermediate
7 steps
ruby
class SyncContactsJob < ApplicationJob queue_as :external_api MAX_CONCURRENCY = 5
Rate-limited CRM sync in a Rails job
background-jobs
rate-limiting
redis
Advanced
9 steps
python
import threading from functools import wraps
A thread-safe debounce decorator in Python
decorators
debounce
threading
Advanced
6 steps
ruby
module DeepImmutable module_function def deep_freeze(obj)
Deep-freezing config with recursive immutability
immutability
recursion
deep-copy
Intermediate
8 steps
rust
use axum::{ extract::State, http::StatusCode, Json,
Idempotent webhook handling in Axum
deduplication
idempotency
shared-state
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.