AuroraMeter.Tenant behaviour (Aurora Meter v1.0.0)

View Source

Resolves an opaque tenant term into a stable string key.

Tenants are never assumed to be strings or integers. A host may pass a struct, a tuple, or any identifier. The configured implementation (:tenant, default AuroraMeter.Tenant.Default) turns it into the tenant_key used everywhere in storage, ETS, and PubSub topics.

What a good tenant is

Use the thing that owns the subscription: the organisation, workspace or account, not the individual user (two users in one org must share one set of counters). The key must be stable for the customer's whole life and unique across customers, so a database primary key or a slug works, an email address does not. Keep it short: it is stored on every counter row and appears in every PubSub topic.

AuroraMeter.track("org_42", :api_calls)        # default resolver, as-is
AuroraMeter.track(42, :api_calls)              # default resolver, "42"
AuroraMeter.track(%MyApp.Org{id: 42}, :api_calls) # needs a custom resolver

A custom resolver is a few lines:

defmodule MyApp.Tenant do
  @behaviour AuroraMeter.Tenant

  @impl true
  def to_key(%MyApp.Accounts.Org{id: id}), do: "org_#{id}"
  def to_key(%MyApp.Accounts.Scope{org_id: id}), do: "org_#{id}"
  def to_key(key) when is_binary(key), do: key
end

# config/config.exs
config :aurora_meter, tenant: MyApp.Tenant

What an implementation must return

A non-empty binary, always. Two rules follow from that and both are part of the contract:

  • A binary is passed through unchanged. Aurora Meter Pro hands stored tenant_key values straight back to facade functions, which accept any term, so an implementation that rewrote an already-resolved key would meter Pro's work against a different tenant. AuroraMeter.Tenant.Default satisfies this; a custom one must too, which is the to_key(key) when is_binary(key), do: key clause in the example above.
  • "" is not a key. An empty key used to be accepted, and every tenant whose resolver could not answer then shared one set of counters. In this release it warns once per node; in Aurora Meter 1.0 it raises. Anything that is not a binary raises in both.

Summary

Callbacks

Converts a tenant term into its stable string key.

Functions

Resolves tenant to its string key via the configured implementation.

Callbacks

to_key(tenant)

@callback to_key(tenant :: term()) :: String.t()

Converts a tenant term into its stable string key.

Functions

to_key(tenant)

@spec to_key(term()) :: String.t()

Resolves tenant to its string key via the configured implementation.

Examples

iex> AuroraMeter.Tenant.to_key("org_42")
"org_42"