AuroraMeter.Config (Aurora Meter v1.0.0)

View Source

Reads and validates Aurora Meter configuration from the :aurora_meter application environment.

Configuration is validated once at boot by validate!/0 (called from AuroraMeter.start_link/1), which fails fast on a missing required key, a wrong type, or a module-typed key naming a module that does not implement its behaviour. Typed accessors below return the effective value; every default is written once, in the schema, and read back from it.

validate!/0 sees the whole application environment, so a misspelled key is reported rather than silently discarded. In this release it is a warning; in Aurora Meter 1.0 it stops the boot. See Configuration for the upgrade sequence.

Summary

Functions

Milliseconds between live PubSub broadcasts of touched counters.

The configured clock. Every instant and date in lib/ comes from it.

Whether nodes exchange deltas and totals so counters are cluster-wide (default true).

Currency code for new credit balance rows (default "usd").

The low-balance callback (fun/1), or nil.

Milliseconds one :credits_low_balance_handler call may take before it is killed.

Default low-balance threshold in micro-dollars, or nil for none.

Micro-dollars the available credit balance may go below zero on a hold or debit (default 0).

The plan id used for tenants with no subscription.

Features that also write a durable event row on every track.

Seconds an occurred_at may run ahead of the node clock before it is refused.

The configured AuroraMeter.Events.Outbox implementation, or nil for none.

Where feature's commercial quantity comes from: :buffered or :events.

The :feature_sources map as configured.

Milliseconds between durable flushes of dirty counters to the database.

The configured identity for this node's "flush:<node>" heartbeat row, or nil when nothing is configured.

Days a flush receipt is kept before AuroraMeter.Retention may delete it (default 30, floor 1 day).

Whether UTC day buckets are maintained for AuroraMeter.history/3 (default true).

The {module, function} pair on_mount {AuroraMeter.LiveView, :subscribe} calls to resolve the tenant, or nil when the host passes a resolver at the mount instead.

Whether the metrics presets tag on :feature (default false).

Milliseconds between gauge samples, or 0 for no internal timers.

The largest counters table the cluster lag gauge will scan for unreconciled_keys; above it the measurement is omitted rather than zeroed.

The configured period source.

Whether an edited plan version refuses the boot or logs.

The configured plans module.

The undeclared-feature policy in force for feature.

The configured billing provider.

The configured host Phoenix.PubSub server name.

How many callers may hold an open record transaction at once.

Milliseconds one durable write may take before it is {:unavailable, :timeout}.

Days a finished replay checkpoint row is kept (default 365, floor 1 day).

The configured host Ecto repo.

The configured storage adapter.

Milliseconds a subscription lookup stays cached (default 5_000; 0 disables).

The configured tenant-resolution module.

What the entitlement functions do with a feature the tenant's plan does not declare.

Validates the current :aurora_meter configuration, raising on any problem.

Functions

broadcast_interval()

@spec broadcast_interval() :: pos_integer()

Milliseconds between live PubSub broadcasts of touched counters.

clock()

@spec clock() :: module()

The configured clock. Every instant and date in lib/ comes from it.

cluster_sync?()

@spec cluster_sync?() :: boolean()

Whether nodes exchange deltas and totals so counters are cluster-wide (default true).

credits_currency()

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

Currency code for new credit balance rows (default "usd").

credits_hold_reconciler()

@spec credits_hold_reconciler() ::
  module() | {module(), atom()} | (map() -> term()) | nil

How AuroraMeter.Credits.reconcile_holds/1 decides about a stale hold.

nil, the default, means every hold is kept. That is the value a host that has never heard of this key has, and it is why upgrading cannot release money.

Examples

iex> AuroraMeter.Config.credits_hold_reconciler()
nil

credits_hold_reconciler_timeout()

@spec credits_hold_reconciler_timeout() :: pos_integer()

Milliseconds one AuroraMeter.Credits.HoldReconciler.decide/1 call may take.

Examples

iex> AuroraMeter.Config.credits_hold_reconciler_timeout()
5000

credits_low_balance_handler()

@spec credits_low_balance_handler() :: (map() -> term()) | nil

The low-balance callback (fun/1), or nil.

credits_low_balance_handler_timeout()

@spec credits_low_balance_handler_timeout() :: pos_integer()

Milliseconds one :credits_low_balance_handler call may take before it is killed.

Examples

iex> AuroraMeter.Config.credits_low_balance_handler_timeout()
5000

credits_low_balance_threshold()

@spec credits_low_balance_threshold() :: integer() | nil

Default low-balance threshold in micro-dollars, or nil for none.

credits_overdraft_tolerance()

@spec credits_overdraft_tolerance() :: non_neg_integer()

Micro-dollars the available credit balance may go below zero on a hold or debit (default 0).

default_plan()

@spec default_plan() :: atom()

The plan id used for tenants with no subscription.

durable_features()

@spec durable_features() :: [atom()]

Features that also write a durable event row on every track.

events_future_tolerance()

@spec events_future_tolerance() :: non_neg_integer()

Seconds an occurred_at may run ahead of the node clock before it is refused.

events_outbox()

@spec events_outbox() :: module() | nil

The configured AuroraMeter.Events.Outbox implementation, or nil for none.

feature_source(feature)

@spec feature_source(atom()) :: :buffered | :events

Where feature's commercial quantity comes from: :buffered or :events.

Anything the configuration does not name is :buffered, which is every feature in 0.4.x and the default in 1.0. This is the one seam that answers the question: the AuroraMeter.track/4 and AuroraMeter.reserve/2,3 guards, the AuroraMeter.with_quota/4 commit rule, cold seeding and the record path's export eligibility all read it here rather than each consulting the map.

The source is a boot-time property. It is read from the cache validate!/0 fills, so changing :feature_sources at runtime changes nothing on this node until it is validated again. That is deliberate: a source that could change between two calls in one period is precisely the double-count this key exists to prevent.

Examples

iex> AuroraMeter.Config.feature_source(:ai_generations)
:buffered

feature_sources()

@spec feature_sources() :: %{required(atom()) => :buffered | :events}

The :feature_sources map as configured.

This is the declaration. feature_source/1 is what is in force on this node, which is the declaration as it stood at the last validate!/0; the two differ only for a host that rewrites the key at runtime, which is documented in Metering as unsupported.

flush_interval()

@spec flush_interval() :: pos_integer()

Milliseconds between durable flushes of dirty counters to the database.

flush_node_id()

@spec flush_node_id() :: String.t() | nil

The configured identity for this node's "flush:<node>" heartbeat row, or nil when nothing is configured.

nil means "use to_string(node())", which AuroraMeter.Retention.node_id/0 resolves. It is not resolved here because a default is written once, in the schema, and node() is not a value a compile-time schema can hold.

On an unnamed VM node() is :nonode@nohost for every node, so several unnamed VMs sharing one database write one heartbeat row between them, which cannot distinguish one node from ten. AuroraMeter.Retention logs a warning when it sees that name.

Examples

iex> AuroraMeter.Config.flush_node_id()
nil

flush_receipt_retention()

@spec flush_receipt_retention() :: pos_integer()

Days a flush receipt is kept before AuroraMeter.Retention may delete it (default 30, floor 1 day).

Examples

iex> AuroraMeter.Config.flush_receipt_retention()
30

history?()

@spec history?() :: boolean()

Whether UTC day buckets are maintained for AuroraMeter.history/3 (default true).

live_view_tenant()

@spec live_view_tenant() :: {module(), atom()} | nil

The {module, function} pair on_mount {AuroraMeter.LiveView, :subscribe} calls to resolve the tenant, or nil when the host passes a resolver at the mount instead.

Examples

iex> AuroraMeter.Config.live_view_tenant()
nil

metrics_feature_label?()

@spec metrics_feature_label?() :: boolean()

Whether the metrics presets tag on :feature (default false).

Examples

iex> AuroraMeter.Config.metrics_feature_label?()
false

metrics_interval()

@spec metrics_interval() :: non_neg_integer()

Milliseconds between gauge samples, or 0 for no internal timers.

Returns whatever the host configured. The default is 10_000, and this repository's own test configuration sets 0, which is why the figure is stated here rather than shown as an example: an example that asserts a configured value is a test of the configuration it happens to run under.

metrics_scan_ceiling()

@spec metrics_scan_ceiling() :: non_neg_integer()

The largest counters table the cluster lag gauge will scan for unreconciled_keys; above it the measurement is omitted rather than zeroed.

Examples

iex> AuroraMeter.Config.metrics_scan_ceiling()
50_000

period_source()

@spec period_source() :: module()

The configured period source.

plan_version_conflict()

@spec plan_version_conflict() :: :raise | :warn

Whether an edited plan version refuses the boot or logs.

Examples

iex> AuroraMeter.Config.plan_version_conflict() in [:raise, :warn]
true

plans()

@spec plans() :: module()

The configured plans module.

policy_for(feature)

@spec policy_for(atom()) :: :allow | :warn | :deny | :raise

The undeclared-feature policy in force for feature.

In V1 every feature gets the global :undeclared_feature_policy. It is a function rather than a key read so that the durable-event writers arriving in 1.0 (record and correct) consult one seam, and so a per-feature map later is a change in one place.

Examples

iex> AuroraMeter.Config.policy_for(:ai_generations) in [:allow, :warn, :deny, :raise]
true

provider()

@spec provider() :: module()

The configured billing provider.

pubsub()

@spec pubsub() :: atom()

The configured host Phoenix.PubSub server name.

record_max_concurrency()

@spec record_max_concurrency() :: pos_integer()

How many callers may hold an open record transaction at once.

record_timeout()

@spec record_timeout() :: pos_integer()

Milliseconds one durable write may take before it is {:unavailable, :timeout}.

replay_checkpoint_retention()

@spec replay_checkpoint_retention() :: pos_integer()

Days a finished replay checkpoint row is kept (default 365, floor 1 day).

Examples

iex> AuroraMeter.Config.replay_checkpoint_retention()
365

repo()

@spec repo() :: module()

The configured host Ecto repo.

storage()

@spec storage() :: module()

The configured storage adapter.

subscription_cache_ttl()

@spec subscription_cache_ttl() :: non_neg_integer()

Milliseconds a subscription lookup stays cached (default 5_000; 0 disables).

tenant()

@spec tenant() :: module()

The configured tenant-resolution module.

undeclared_feature_policy()

@spec undeclared_feature_policy() :: :allow | :warn | :deny | :raise

What the entitlement functions do with a feature the tenant's plan does not declare.

validate!()

@spec validate!() :: keyword()

Validates the current :aurora_meter configuration, raising on any problem.

Returns the validated options (with defaults applied) on success.

Examples

iex> is_list(AuroraMeter.Config.validate!())
true