portunus_machine_aux (portunus v0.14.0)
View SourcePure decision logic for portunus_machine's aux renewal and expiry sweep.
Aux state is per-server, in-memory and never replicated. Renewal writes
nothing to the Raft log. Only expiry becomes a logged
{expire_leases, ...} command.
The rules match the etcd lessor:
- every lease's operative deadline lives here, on the leader, in monotonic time. Renewal moves it forward without touching the log
- a lease known to the machine but missing from
deadlinesis seeded at its full TTL. A new leader, a restarted server and a fresh grant all err toward late expiry, never early - an expiry proposal carries the lease's
refreshedindex as a fence. While the machine still holds the lease at that exact index, the proposal is live: renewals answerlease_expiredand the sweep does not re-propose. Anything that changesrefreshedor removes the lease voids the entry - a term change means another leader renewed these holders in between, so both maps are cleared first
Every function takes the applied leases as a lease_view() map
(#{lease_id() => {ttl_ms, refreshed}}), the current Raft term and a
caller-supplied monotonic now.
This means that the decisions can be tested without a Ra cluster.
portunus_machine:handle_aux/5 extracts the
inputs and turns the outputs into effects.
Summary
Functions
As the name suggests, this function is called on every leader tick.
A non-leader holds no deadlines. Clears both maps.
Called once a grant_lease command has been committed, whether it created the
lease or was a repeat grant by the same owner.
Renews each lease the machine still holds that has no live expiry proposal.
Types
-opaque aux()
-type expire_pair() :: {portunus:lease_id(), ra:index()}.
-type lease_view() :: #{portunus:lease_id() => {pos_integer(), ra:index()}}.
Functions
-spec leader_tick(aux(), lease_view(), non_neg_integer(), integer()) -> {aux(), [expire_pair()]}.
As the name suggests, this function is called on every leader tick.
Reconciles the term, drops entries for leases
the machine no longer holds, seeds untracked leases at their full TTL, then
proposes expiry for every deadline at or past Now that doesn't already have
a live proposal.
Returns the pairs to append as one {expire_leases, ...}
command. Pairs are sorted so that tests observe a stable order.
-spec new() -> aux().
A non-leader holds no deadlines. Clears both maps.
-spec refreshed(aux(), lease_view(), non_neg_integer(), integer(), [portunus:lease_id()]) -> aux().
Called once a grant_lease command has been committed, whether it created the
lease or was a repeat grant by the same owner.
Resets each granted lease's
aux deadline to a full TTL (Now + Ttl) so that a lease whose old deadline
had already passed is not removed as expired right after its grant succeeded.
-spec renew(aux(), lease_view(), non_neg_integer(), integer(), [portunus:lease_id()]) -> {aux(), [{portunus:lease_id(), ok | {error, lease_expired}}]}.
Renews each lease the machine still holds that has no live expiry proposal.
A lease with a live proposal answers lease_expired even
though the command has not applied yet. The appended command may still
expire it, so acknowledging the renewal would be wrong.