Jido.Signal.ID (Jido Signal v1.0.0)

View Source

Manages UUID7-based signal IDs for the bus system. Provides utilities for generating, comparing, and extracting information from signal IDs.

UUID7s provide several benefits for signal IDs:

  • Monotonically increasing (timestamp-based)
  • Contain embedded timestamps and sequence numbers
  • High uniqueness guarantees within the same millisecond
  • Good sequential scanning performance

UUID7 Format:

  • First 48 bits: Unix timestamp in milliseconds
  • Next 12 bits: Sequence number (monotonic counter within each millisecond)
  • Remaining bits: Random data

This ensures that:

  1. IDs are globally ordered by timestamp
  2. IDs generated in the same millisecond are ordered by sequence number
  3. IDs with same timestamp and sequence are ordered lexicographically

Usage Examples

# Generate UUID7
{id, timestamp} = Jido.Signal.ID.generate()

# Compare IDs chronologically
:lt = Jido.Signal.ID.compare(older_id, newer_id)

# Extract components
timestamp = Jido.Signal.ID.extract_timestamp(id)
sequence = Jido.Signal.ID.sequence_number(id)

Summary

Functions

Compares two UUID7s chronologically. Returns :lt, :eq, or :gt based on the following order

Extracts the Unix timestamp (in milliseconds) from a UUID7 string. UUID7 embeds a 48-bit timestamp in its first 6 bytes.

Formats a timestamp and sequence as a sortable string. Useful for version strings or ordering.

Generates a new signal ID using UUID7.

Generates a new signal ID using UUID7, returning just the UUID string.

Generates multiple sequential UUIDs in a batch. All UUIDs will be strictly ordered and unique within the same millisecond. If the batch size would exceed the available sequence numbers (4096), it will use multiple milliseconds.

Generates a UUID7 with a specific timestamp and sequence number. This ensures strict ordering of IDs within the same millisecond.

Returns the sequence number portion of the UUID7. This is a 12-bit monotonic counter within each millisecond.

Validates that a string is a valid UUID7. Returns true if the input is a valid UUID7 string, false otherwise.

Types

comparison_result()

@type comparison_result() :: :lt | :eq | :gt

timestamp()

@type timestamp() :: non_neg_integer()

uuid7()

@type uuid7() :: String.t()

Functions

compare(uuid1, uuid2)

@spec compare(uuid7(), uuid7()) :: comparison_result()

Compares two UUID7s chronologically. Returns :lt, :eq, or :gt based on the following order:

  1. Timestamp comparison
  2. If timestamps match, sequence number comparison
  3. If both match, lexicographical comparison of remaining bits

Examples

Jido.Signal.ID.compare(older_id, newer_id)
#=> :lt

Jido.Signal.ID.compare(newer_id, older_id)
#=> :gt

Jido.Signal.ID.compare(id, id)
#=> :eq

extract_timestamp(uuid)

@spec extract_timestamp(uuid7()) :: timestamp()

Extracts the Unix timestamp (in milliseconds) from a UUID7 string. UUID7 embeds a 48-bit timestamp in its first 6 bytes.

Examples

ts = Jido.Signal.ID.extract_timestamp("018df6f0-1234-7890-abcd-ef0123456789")
#=> 1677721600000

format_sortable(uuid)

@spec format_sortable(uuid7()) :: String.t()

Formats a timestamp and sequence as a sortable string. Useful for version strings or ordering.

Returns a string in the format "timestamp-sequence".

Examples

Jido.Signal.ID.format_sortable("018df6f0-1234-7890-abcd-ef0123456789")
#=> "1677721600000-42"

generate()

@spec generate() :: {uuid7(), timestamp()}

Generates a new signal ID using UUID7.

Returns a tuple containing the generated ID and its embedded timestamp. The timestamp is in Unix milliseconds.

Examples

{id, ts} = Jido.Signal.ID.generate()
#=> {"018df6f0-1234-7890-abcd-ef0123456789", 1677721600000}

generate!()

@spec generate!() :: uuid7()

Generates a new signal ID using UUID7, returning just the UUID string.

Examples

id = Jido.Signal.ID.generate!()
#=> "018df6f0-1234-7890-abcd-ef0123456789"

generate_batch(count)

@spec generate_batch(pos_integer()) :: {[uuid7()], timestamp()}

Generates multiple sequential UUIDs in a batch. All UUIDs will be strictly ordered and unique within the same millisecond. If the batch size would exceed the available sequence numbers (4096), it will use multiple milliseconds.

Examples

{ids, timestamp} = Jido.Signal.ID.generate_batch(5)
#=> {["018df6f0-0001-...", "018df6f0-0002-..."], 1677721600000}

# Verify ordering
[id1, id2 | _] = ids
:lt = Jido.Signal.ID.compare(id1, id2)

generate_sequential(timestamp, sequence)

@spec generate_sequential(timestamp(), non_neg_integer()) :: uuid7()

Generates a UUID7 with a specific timestamp and sequence number. This ensures strict ordering of IDs within the same millisecond.

Parameters

  • timestamp - Unix timestamp in milliseconds
  • sequence - A number between 0 and 4095 (12 bits)

Examples

id = Jido.Signal.ID.generate_sequential(timestamp, 1)
#=> "018df6f0-0001-7890-abcd-ef0123456789"

sequence_number(uuid)

@spec sequence_number(uuid7()) :: non_neg_integer()

Returns the sequence number portion of the UUID7. This is a 12-bit monotonic counter within each millisecond.

Examples

seq = Jido.Signal.ID.sequence_number("018df6f0-1234-7890-abcd-ef0123456789")
#=> 42

valid?(uuid)

@spec valid?(term()) :: boolean()

Validates that a string is a valid UUID7. Returns true if the input is a valid UUID7 string, false otherwise.

Examples

Jido.Signal.ID.valid?("018df6f0-1234-7890-abcd-ef0123456789")
#=> true

Jido.Signal.ID.valid?("not-a-uuid")
#=> false