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.
Functions
@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.
@spec monotonic_ms() :: integer()
A monotone millisecond reading, for an in-memory elapsed span only.
@spec now() :: DateTime.t()
The node's current instant. Cheap, wall-clock shaped, and not monotone.
@spec today() :: Date.t()
The UTC date of now/0, derived from the same reading.