TermUI.EventQueue (TermUI v1.0.0)
View SourceBounded event queue for preventing DoS via event flooding.
This module implements a fixed-size queue with a drop-oldest strategy to prevent unbounded memory growth from rapid event input.
Design
The queue uses Erlang's :queue module for efficient operations:
- O(1) amortized for enqueue/dequeue
- O(1) for length checks
When the queue is full and a new event arrives, the oldest event is dropped and a warning is logged (rate-limited).
Example
# Create a new queue with max size
queue = EventQueue.new(max_size: 1000)
# Add an event
{:ok, queue} = EventQueue.push(queue, :some_event)
# Drop oldest when full
{{:dropped, oldest_event}, queue} = EventQueue.push(queue, :new_event)
# Take next event
{{:value, event}, queue} = EventQueue.pop(queue)
{:empty, queue} = EventQueue.pop(queue)
Summary
Types
Pop result - value, empty, or timeout
Push result - either success or dropped event
Event queue structure
Functions
Clears all events from the queue.
Returns the number of events that have been dropped due to overflow.
Returns whether the queue is empty.
Returns whether the queue is full.
Default maximum queue size.
Returns the maximum size of the queue.
Creates a new event queue with the given options.
Peeks at the next event without removing it.
Pops the next event from the queue.
Pushes an event onto the queue.
Pushes an event onto the queue, dropping oldest if full.
Resets the dropped event counter to zero.
Returns the current size of the queue.
Converts the queue to a list for inspection/testing.
Warning rate limit in milliseconds (log once per 5 seconds max).
Types
Pop result - value, empty, or timeout
Push result - either success or dropped event
@type t() :: %TermUI.EventQueue{ dropped_count: non_neg_integer(), last_warning: integer() | nil, max_size: pos_integer(), queue: :queue.queue(), size: non_neg_integer() }
Event queue structure
Functions
Clears all events from the queue.
@spec dropped_count(t()) :: non_neg_integer()
Returns the number of events that have been dropped due to overflow.
This counter is cumulative for the lifetime of the queue.
Returns whether the queue is empty.
Returns whether the queue is full.
Default maximum queue size.
This value balances memory usage with responsiveness:
- It bounds memory during input bursts
- The runtime drains queued events in batches, so queue size is not a time duration or a fixed number of rendered frames
@spec max_size(t()) :: pos_integer()
Returns the maximum size of the queue.
Creates a new event queue with the given options.
Options
:max_size- Maximum number of events in queue (default: 1000)
Example
queue = EventQueue.new()
queue = EventQueue.new(max_size: 500)
@spec peek(t()) :: pop_result()
Peeks at the next event without removing it.
Returns
{{:value, event}, queue}- Next event{:empty, queue}- Queue is empty
@spec pop(t()) :: pop_result()
Pops the next event from the queue.
Returns
{{:value, event}, queue}- Next event{:empty, queue}- Queue is empty
Example
{{:value, event}, queue} = EventQueue.pop(queue)
{:empty, queue} = EventQueue.pop(queue)
@spec push(t(), term()) :: push_result()
Pushes an event onto the queue.
If the queue is full, the oldest event is dropped and returned.
Returns
{:ok, queue}- Event was added{{:dropped, oldest_event}, queue}- Queue was full, oldest event dropped
Example
{:ok, queue} = EventQueue.push(queue, :event)
{{:dropped, oldest}, queue} = EventQueue.push(queue, :new_event)
Pushes an event onto the queue, dropping oldest if full.
Similar to push/2 but always returns the updated queue without
indicating whether a drop occurred. Use dropped_count/1 to check
for drops.
Resets the dropped event counter to zero.
@spec size(t()) :: non_neg_integer()
Returns the current size of the queue.
Converts the queue to a list for inspection/testing.
Events are ordered from oldest to newest (front to back).
Warning rate limit in milliseconds (log once per 5 seconds max).