AuroraMeter. Event
(Aurora Meter v1.0.0)
View Source
A recorded usage fact, as Aurora Meter hands it back.
This is a read struct. Hosts pattern match on it and read its fields;
nothing outside the library builds one. It is the return shape of
AuroraMeter.record/4, record_batch/2 and correct/4, and of
AuroraMeter.Events.get/2 and stream/2.
Fields
id: the row's internal UUID, assigned by the database. Useful in a support conversation and nowhere else. It is not the identity of the fact;event_idis.event_id: the caller's identity for this fact, unique per tenant, at most 128 bytes. Recording twice with the sameevent_idand the same payload is a duplicate, not a second fact.tenant_key: the resolved tenant key.feature: the feature atom.quantity: a positive integer.kind::usageor:correction.original_event_id: for a correction, theevent_idof the fact it corrects, in the same tenant.nilfor a usage event.occurred_at: when the usage happened, as the caller stated it.recorded_at: when Aurora Meter wrote the row. The same column the Ecto schema callsinserted_at.period_start: the start of the billing window the fact is charged to.period_source: the period source module that resolved it, as a string.dimensions: the caller's breakdown keys, string keys and scalar values.metadata: the caller's free-form map.plan_id,plan_version: the plan in force when the usage occurred. Recorded for attribution, never used to reprice (decision D05).attribution: how much to trust the period and plan on this row.durability::durablewhen the row is committed,:conditionalwhen it was written inside a transaction the host still owns.seq: the row's insertion order, assigned by a database sequence.
The attribution vocabulary
:resolved: the period source placedoccurred_atin a window without ambiguity, and the plan in force at that instant was resolved. Both the period and the plan on this row are facts.:plan_unresolved: the period is a fact and the plan is not there. The tenant had no subscription at all, or none that coversoccurred_at, so there is no commercial contract to name.plan_idandplan_versionare NULL, and they are NULL rather than today's plan on purpose: substituting the current plan for a historical fact is exactly the repricing decision D05 forbids. Build unit 07c added this value; before it, every row whose period resolved said:resolvedand carried no plan at all.:unresolved: the source could not place the instant, so the calendar month containing it was used instead. The period on this row is an approximation, and this value is how you tell. The plan is not resolved either, and deliberately not even attempted: a period this code had to guess is not an instant worth resolving a contract against.:legacy_track: the row was written byAuroraMeter.track/4before the durable path existed, and given an identity afterwards bymix aurora_meter.events.backfill. Itsoccurred_atis the instant the row was written, not the instant the usage happened, and it was never billed.
The vocabulary is a list, not a database constraint, so a later release can add a kind of attribution without a migration. Match on the values you know and treat an unknown one as untrusted.
Summary
Types
How much to trust the period and plan recorded on an event.
Whether the row is committed, or still inside a transaction the host owns.
Types
@type attribution() :: :resolved | :plan_unresolved | :unresolved | :legacy_track | String.t()
How much to trust the period and plan recorded on an event.
@type durability() :: :durable | :conditional
Whether the row is committed, or still inside a transaction the host owns.
@type t() :: %AuroraMeter.Event{ attribution: attribution() | nil, dimensions: map(), durability: durability(), event_id: String.t() | nil, feature: atom(), id: String.t(), kind: :usage | :correction, metadata: map(), occurred_at: DateTime.t() | nil, original_event_id: String.t() | nil, period_source: String.t() | nil, period_start: DateTime.t() | nil, plan_id: String.t() | nil, plan_version: String.t() | nil, quantity: integer(), recorded_at: DateTime.t(), seq: integer() | nil, tenant_key: String.t() }