ExBooking. Assignment
(ExBooking v0.2.1)
View Source
Deterministic resource assignment.
Assignment runs after availability has already established which resources can take the slot. Strategies use explicit fairness inputs from the caller, then fall back to resource id so ties are stable and replayable.
A scorer may rank resources before the strategy key. The scorer receives the request routing context as opaque data; the kernel never inspects CRM, GTM, territory, or enrichment semantics.
Example
iex> slot = ExBooking.Interval.new!(~U[2026-07-13 09:00:00Z], ~U[2026-07-13 09:30:00Z])
...>
...> resources = [
...> %ExBooking.Resource{id: "b", timezone: "Etc/UTC"},
...> %ExBooking.Resource{id: "a", timezone: "Etc/UTC"}
...> ]
...>
...> {:ok, [winner]} = ExBooking.Assignment.assign(resources, slot, [])
...> winner.id
"a"
Summary
Functions
Picks the resource(s) that take a booking for slot.
Validates a strategy and any fairness inputs it consumes.
Validates strategy and scorer options independently of resource data.
Types
@type base_strategy() ::
:first_available
| :round_robin
| :least_recently_booked
| :weighted
| :priority
Assignment strategy selector.
@type scorer() :: (ExBooking.Resource.t(), map() -> number())
Opaque scoring hook over routing context.
@type strategy() :: base_strategy() | {:owner_first, owner_id: String.t(), fallback: base_strategy()}
Functions
@spec assign([ExBooking.Resource.t()], ExBooking.Interval.t(), keyword()) :: {:ok, [ExBooking.Resource.t()]} | {:error, :no_eligible_resource | {:invalid, atom(), term()}}
Picks the resource(s) that take a booking for slot.
Options: :strategy (default :first_available), :scorer,
:routing_context (passed to the scorer), :participants (default :one),
and :capacity_required (for :pool).
Examples
iex> resources = [
...> %ExBooking.Resource{id: "b", timezone: "Etc/UTC"},
...> %ExBooking.Resource{id: "a", timezone: "Etc/UTC"}
...> ]
...>
...> slot = ExBooking.Interval.new!(~U[2026-07-13 09:00:00Z], ~U[2026-07-13 09:30:00Z])
...>
...> {:ok, [winner]} =
...> ExBooking.Assignment.assign(resources, slot, strategy: :first_available)
...>
...> winner.id
"a"
@spec validate([ExBooking.Resource.t()], keyword()) :: :ok | {:error, {:invalid, atom(), term()}}
Validates a strategy and any fairness inputs it consumes.
Validation is separate from selection so callers can reject malformed input before performing availability work.
Example
iex> resource = %ExBooking.Resource{id: "resource_1", timezone: "Etc/UTC"}
...> ExBooking.Assignment.validate([resource], strategy: :round_robin)
:ok
Validates strategy and scorer options independently of resource data.
Other keys belong to the calling operation and are checked by its option schema.
Examples
iex> ExBooking.Assignment.validate_options(strategy: :round_robin)
:ok
iex> ExBooking.Assignment.validate_options(strategy: :random)
{:error, {:invalid, :strategy, :random}}