AuroraMeter.Clock.System (Aurora Meter v1.0.0)

View Source

The default clock, and the only value supported in production.

now/0 makes no monotonicity promise, and that is deliberate

now/0 reads System.system_time/1 rather than DateTime.utc_now/0. The reason is cost, not correctness: about 31 ns against 323 ns, and AuroraMeter.track/4 reads it on every increment.

Neither is monotone, and there is no monotone wall clock to be had. Measured on the development host over 420 seconds under load, 337,900,054 samples of each reading: DateTime.utc_now/0 and System.os_time/1 each stepped backwards 13 times (largest 1.330921 s), and System.system_time/1 stepped backwards 6 times and further (largest 2.647191 s) on an exact 60 second offset-resync cadence, which multi_time_warp, the OTP 29 default, licenses. +C no_time_warp removes it, but the host owns +C and this is a library, so a VM flag is a diagnosis and never a remedy. The full measurement, the six candidate bases and the decision are in docs/evidence/v1/phase-02/02c-clock-choice.md.

So: do not compare now/0 against a persisted timestamp. Use db_now/0, and stamp the row with the database too.

today/0 is the date of now/0, never a second clock read.

db_now/0

SELECT clock_timestamp() AT TIME ZONE 'UTC' through the configured repo. clock_timestamp() rather than now() because now() is the transaction's start time and would return the same instant for every call inside one transaction, which is exactly wrong for "has enough time passed".

With no repo configured it raises an ArgumentError naming the repo key rather than falling back to a node clock: a silent fallback would reintroduce the two-clock comparison this exists to remove. The SQL is Postgres; a storage adapter for something else configures its own clock module.

Summary

Functions

The database's current instant, from clock_timestamp() through the configured repo. Raises an ArgumentError naming the repo key when none is configured.

A monotone millisecond reading, for an in-memory elapsed span only.

The node's current instant. Cheap, wall-clock shaped, and not monotone.

The UTC date of now/0, derived from the same reading.

Functions

db_now()

@spec db_now() :: DateTime.t()

The database's current instant, from clock_timestamp() through the configured repo. Raises an ArgumentError naming the repo key when none is configured.

monotonic_ms()

@spec monotonic_ms() :: integer()

A monotone millisecond reading, for an in-memory elapsed span only.

now()

@spec now() :: DateTime.t()

The node's current instant. Cheap, wall-clock shaped, and not monotone.

today()

@spec today() :: Date.t()

The UTC date of now/0, derived from the same reading.