Expand description
rustlavel-ledger: a book that balances.
An application that sells credits has a number per customer that must be right — not approximately right, not right after a nightly job, right now and under load. This crate is that number and the rules around it.
§Double entry
Every movement of value is a Transfer between two Accounts, and
writes two Entry rows: a debit on one and a credit on the other, equal
and opposite. Where does a top-up come from? A system account,
system:topup. Where does a spent credit go? system:consumption. So
the sum of every balance in the book is zero, always, and Ledger::audit
can say whether it is. A single-entry design — “add 100 to the user” — has
no such check, and its errors are invisible until a customer complains.
§What is atomic, and how
Every operation is one database transaction. The debit is
UPDATE … SET balance = balance - ? WHERE id = ? AND balance - held >= ?,
and the row count is the answer: zero means the funds were not there, and
nothing else has happened yet. That guard is also the lock — the database
serialises two transactions writing the same row — so two consumers racing
for the last credit cannot both have it. Measured in this crate’s tests.
§Holds
A job that will cost 50 credits and take a minute must not find the
balance gone when it finishes. Ledger::hold reserves the amount up
front (it leaves balance and raises held; available is the
difference), and the job ends with Ledger::capture or
Ledger::release. Both are a compare-and-set on the hold’s status, so a
hold cannot be captured twice. A hold has a lifetime; Ledger::sweep
releases the ones nobody came back for.
§Expiry
Credits bought in March may be gone in May. Each top-up is a [Lot] with
an expiry, consumption draws from the lot that expires first, and
Ledger::sweep moves what is left in a dead lot to system:expiry — as
a transfer, so it shows in the history like everything else.
Re-exports§
pub use account::Account;pub use account::Balance;pub use account::SYSTEM_CONSUMPTION;pub use account::SYSTEM_EXPIRY;pub use account::SYSTEM_TOPUP;pub use entry::Entry;pub use entry::Transfer;pub use entry::TransferKind;pub use hold::Hold;pub use hold::HoldStatus;pub use ledger::Ledger;pub use ledger::Sweep;pub use schema::CreateLedgerTables;pub use schema::create_tables;pub use schema::drop_tables;
Modules§
- account
- An account, and what it holds.
- entry
- A transfer, and the two entries it writes.
- hold
- A reservation against an account.
- ledger
- The operations. Every one is a single transaction.
- schema
- The five tables.
Enums§
- Error
- Every failure the framework itself can produce.
Type Aliases§
- Result
- The framework-wide result type.