Skip to main content

cross_platform_realtime_dir_watcher

🔍 Cross-Platform Real-Time Directory Watcher with Event Batching​

Building a robust watcher requires handling different backends (inotify, FSEvents, Windows APIs) and coalescing noisy events (e.g., editor temp writes). This example uses rb-inotify on Linux and rb-fsevent on macOS, unified under a concurrent queue with batch de‑duplication.

require 'rb-inotify'
require 'rb-fsevent'
require 'concurrent-ruby'

class DirectoryWatcher
def initialize(paths)
@paths = Array(paths)
@queue = Concurrent::Array.new
@mutex = Mutex.new
end

def run
if RUBY_PLATFORM =~ /darwin/
@watcher = FSEvent.new
@watcher.watch(@paths, file_events: true) { |directories| enqueue(directories) }
@watcher.run
else
notifier = INotify::Notifier.new
@paths.each { |p| notifier.watch(p, :modify, :create, :delete, :move) { |e| enqueue([e.name]) } }
notifier.run!
end

process_batches
end

private

def enqueue(events)
@mutex.synchronize { @queue.concat(Array(events)) }
end

def process_batches
loop do
sleep 0.5
@mutex.synchronize do
next if @queue.empty?
batch = @queue.uniq
@queue.clear
handle_batch(batch)
end
end
end

def handle_batch(batch)
batch.each do |file|
# your custom logic: reload, sync, backup, etc.
puts "Detected change in: ", file
end
end
end

# Usage:
DirectoryWatcher.new('/srv/shared_assets').run

This structure:

  • Adapts to platform-specific APIs.
  • Collects events into a concurrent array.
  • Coalesces duplicates every 0.5s to avoid thrash.
  • Processes each unique path in bulk, enabling batched actions.