DevPortAllocator (dev_port_allocator v0.1.0)

Copy Markdown View Source

Resolve development ports dynamically while preserving explicit environment configuration.

This library is framework-agnostic and can be used from config/runtime.exs in Phoenix (or any Elixir app that needs predictable local port allocation). WARNING: This library is intended for development servers only. Do not use it in production deployments.

Typical behavior:

  • If a relevant env var is present, explicit values win.
  • If no explicit env vars are present, probe from a starting port.
  • When the default is busy, return the next available port (or contiguous block).

Summary

Functions

Check if a TCP port is available on localhost.

Resolve a contiguous block of ports.

Types

block_result()

@type block_result() :: %{ports: [pos_integer()], source: source()}

single_result()

@type single_result() :: %{port: pos_integer(), source: source()}

source()

@type source() :: :explicit | :default | :fallback

Functions

port_available?(port, opts \\ [])

@spec port_available?(
  pos_integer(),
  keyword()
) :: boolean()

Check if a TCP port is available on localhost.

resolve_block(env \\ System.get_env(), opts \\ [])

@spec resolve_block(
  map(),
  keyword()
) :: block_result()

Resolve a contiguous block of ports.

Options

  • :env_vars - ordered env var keys for explicit ports
  • :default_port - default base port for the first entry (default: 4000)
  • :start_port - first base port to probe (defaults to :default_port)
  • :block_size - number of contiguous ports to allocate
  • :port_available? - custom availability function for testing
  • :ip - bind address for availability checks (default: {127, 0, 0, 1})

If any :env_vars key is present, allocation is explicit and probing is skipped. Missing explicit keys use implied defaults based on the first port.

resolve_port(env \\ System.get_env(), opts \\ [])

@spec resolve_port(
  map(),
  keyword()
) :: single_result()

Resolve a single port.

Options

  • :env_var - env var key used for explicit value (default: "PORT")
  • :default_port - default preferred port (default: 4000)
  • :start_port - first port to probe when no explicit env var exists
  • :port_available? - custom availability function for testing
  • :ip - bind address for availability checks (default: {127, 0, 0, 1})

Examples

iex> DevPortAllocator.resolve_port(%{}, default_port: 4000, port_available?: fn p -> p == 4000 end)
%{port: 4000, source: :default}

iex> DevPortAllocator.resolve_port(%{"PORT" => "5050"})
%{port: 5050, source: :explicit}