BEAM waiter registry for blocking list commands (BLPOP, BRPOP, BLMOVE, BLMPOP).
Uses an ETS table (:ferricstore_waiters) with entries
{key, client_pid, deadline_ms, registered_at}. When a list is empty, the
client BEAM process registers itself and enters a receive block with an
after clause matching the timeout. When another client pushes to that key,
the push path calls notify_push/1 which wakes the oldest waiter (FIFO by
registration timestamp).
The BEAM runtime handles the timeout with zero polling -- no busy wait, no periodic check loop. Multiple waiters on the same key are served FIFO by registration timestamp.
ETS table
The table is a :duplicate_bag keyed by the watched key. Each entry is:
{key, pid, deadline_ms, registered_at_mono}key-- the Redis key being watchedpid-- the client connection processdeadline_ms-- absolute monotonic deadline (0 = infinite)registered_at_mono--System.monotonic_time(:microsecond)for FIFO ordering
Summary
Functions
Removes all waiters registered by pid.
Returns the number of waiters registered for key.
Initializes the waiter ETS table. Must be called once at application start.
Notifies the oldest waiter for key that a value has been pushed.
Notifies up to count oldest waiters for key.
Registers the calling process as a waiter for key.
Returns the total number of waiters across all keys.
Unregisters a specific waiter for key.
Functions
@spec cleanup(pid()) :: :ok
Removes all waiters registered by pid.
Called when a client disconnects to prevent stale entries.
Parameters
pid-- the disconnected client's pid
@spec count(binary()) :: non_neg_integer()
Returns the number of waiters registered for key.
Useful for testing and monitoring.
@spec init() :: :ok
Initializes the waiter ETS table. Must be called once at application start.
Notifies the oldest waiter for key that a value has been pushed.
Called from the push path (LPUSH/RPUSH) when data is added to a key.
Wakes the oldest registered waiter (FIFO) by sending {:waiter_notify, key}
to its pid. Returns the notified pid, or nil if no waiters exist.
Parameters
key-- the Redis key that received a push
@spec notify_push(binary(), non_neg_integer()) :: [pid()]
Notifies up to count oldest waiters for key.
Multi-element pushes can make more than one blocked list command runnable. Waking at most the pushed element count avoids a thundering herd while still allowing each woken client to re-run the real pop atomically.
@spec register(binary(), pid(), non_neg_integer()) :: :ok
Registers the calling process as a waiter for key.
Parameters
key-- the Redis key to wait onpid-- the client connection process piddeadline_ms-- absolute monotonic deadline in ms (0 = block forever)
Returns
:ok
@spec total_count() :: non_neg_integer()
Returns the total number of waiters across all keys.
Useful for testing and monitoring.
Unregisters a specific waiter for key.
Parameters
key-- the Redis keypid-- the client connection process pid