TermUI.EventQueue (TermUI v1.0.0)

View Source

Bounded 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

t()

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()

@type pop_result() :: {{:value, term()}, t()} | {:empty, t()}

Pop result - value, empty, or timeout

push_result()

@type push_result() :: {:ok, t()} | {{:dropped, term()}, t()}

Push result - either success or dropped event

t()

@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

clear(q)

@spec clear(t()) :: t()

Clears all events from the queue.

dropped_count(event_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.

empty?(event_queue)

@spec empty?(t()) :: boolean()

Returns whether the queue is empty.

full?(event_queue)

@spec full?(t()) :: boolean()

Returns whether the queue is full.

max_size()

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

max_size(event_queue)

@spec max_size(t()) :: pos_integer()

Returns the maximum size of the queue.

new(opts \\ [])

@spec new(keyword()) :: t()

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)

peek(q)

@spec peek(t()) :: pop_result()

Peeks at the next event without removing it.

Returns

  • {{:value, event}, queue} - Next event
  • {:empty, queue} - Queue is empty

pop(q)

@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)

push(q, event)

@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)

push!(q, event)

@spec push!(t(), term()) :: t()

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.

reset_dropped_count(q)

@spec reset_dropped_count(t()) :: t()

Resets the dropped event counter to zero.

size(event_queue)

@spec size(t()) :: non_neg_integer()

Returns the current size of the queue.

to_list(q)

@spec to_list(t()) :: [term()]

Converts the queue to a list for inspection/testing.

Events are ordered from oldest to newest (front to back).

warning_interval()

Warning rate limit in milliseconds (log once per 5 seconds max).