AuroraMeter (Aurora Meter v0.1.0)

View Source

Aurora Meter — real-time usage metering, plan entitlements, and Stripe-ready billing primitives for Phoenix.

Count, gate, and bill on the BEAM: increments hit an in-memory ETS counter (microseconds, no database on the hot path), a flusher persists snapshots to Postgres on an interval, and a broadcaster fans live values out over Phoenix.PubSub.

Add it to your host application's supervision tree — it validates configuration at boot and starts the metering runtime:

children = [
  MyApp.Repo,
  {Phoenix.PubSub, name: MyApp.PubSub},
  AuroraMeter,
  MyAppWeb.Endpoint
]

The public metering/entitlement API (track/4, check/2, with_quota/4, usage/2, remaining/2, subscribe/2) is added in later phases; see plan.md.

Summary

Functions

Whether check/2 currently returns :ok.

Checks whether tenant may use feature. See AuroraMeter.Entitlements.check/2.

Whether the plan grants access to feature (ignores quota).

Returns tenant's current plan. See AuroraMeter.Entitlements.plan/1.

Remaining quota for a hard-limited feature, or :unlimited.

Atomically reserves usage against the plan. See AuroraMeter.Entitlements.reserve/3.

Atomically reserves qty usage against the plan.

Validates configuration and starts the Aurora Meter runtime supervisor.

Assigns plan_id to tenant locally. See AuroraMeter.Entitlements.subscribe/2.

Records qty usage of feature for tenant in the current period.

Returns tenant's usage of feature in the current period.

Returns a map of feature => value for tenant's warm counters this period.

Returns the Aurora Meter version.

Gates, runs, and meters qty in one step.

Functions

allowed?(tenant, feature)

@spec allowed?(term(), atom()) :: boolean()

Whether check/2 currently returns :ok.

check(tenant, feature)

@spec check(term(), atom()) :: :ok | {:error, :limit_exceeded | :not_entitled}

Checks whether tenant may use feature. See AuroraMeter.Entitlements.check/2.

entitled?(tenant, feature)

@spec entitled?(term(), atom()) :: boolean()

Whether the plan grants access to feature (ignores quota).

plan(tenant)

@spec plan(term()) :: AuroraMeter.Plan.t() | nil

Returns tenant's current plan. See AuroraMeter.Entitlements.plan/1.

remaining(tenant, feature)

@spec remaining(term(), atom()) :: non_neg_integer() | :unlimited

Remaining quota for a hard-limited feature, or :unlimited.

reserve(tenant, feature)

@spec reserve(term(), atom()) :: :ok | {:error, :limit_exceeded | :not_entitled}

Atomically reserves usage against the plan. See AuroraMeter.Entitlements.reserve/3.

reserve(tenant, feature, qty)

@spec reserve(term(), atom(), pos_integer()) ::
  :ok | {:error, :limit_exceeded | :not_entitled}

Atomically reserves qty usage against the plan.

start_link(opts \\ [])

@spec start_link(keyword()) :: Supervisor.on_start()

Validates configuration and starts the Aurora Meter runtime supervisor.

Raises NimbleOptions.ValidationError if the :aurora_meter configuration is missing a required key or has a value of the wrong type.

subscribe(tenant, plan_id)

@spec subscribe(term(), atom() | String.t()) ::
  {:ok, AuroraMeter.Schema.Subscription.t()} | {:error, Ecto.Changeset.t()}

Assigns plan_id to tenant locally. See AuroraMeter.Entitlements.subscribe/2.

track(tenant, feature, qty \\ 1, opts \\ [])

@spec track(term(), atom(), integer(), keyword()) :: :ok

Records qty usage of feature for tenant in the current period.

Runs on the ETS hot path (no database round-trip) unless the feature is durable (opts[:durable] or configured in :durable_features), in which case a raw event row is also written. Options: :durable (boolean), :metadata (map).

usage(tenant, feature)

@spec usage(term(), atom()) :: integer()

Returns tenant's usage of feature in the current period.

usage_all(tenant)

@spec usage_all(term()) :: %{required(atom()) => integer()}

Returns a map of feature => value for tenant's warm counters this period.

version()

@spec version() :: String.t()

Returns the Aurora Meter version.

Examples

iex> is_binary(AuroraMeter.version())
true

with_quota(tenant, feature, fun)

@spec with_quota(term(), atom(), (-> result)) :: {:ok, result} | {:error, term()}
when result: term()

Gates, runs, and meters in one step. See AuroraMeter.Entitlements.with_quota/4.

with_quota(tenant, feature, qty, fun)

@spec with_quota(term(), atom(), pos_integer(), (-> result)) ::
  {:ok, result} | {:error, term()}
when result: term()

Gates, runs, and meters qty in one step.