Optional periodOptional resolveAsked by SqlSpendMeter.reconcile for each expired reservation on a meter without resolveExpired, except
one made with requireFence or deferred before, which such a meter leaves reserved. Its answer settles the
reservation only if, when the pass writes it, the reservation is still the attempt asked about, still past its
lease and still unfenced: one an opted-in pass defers, or a heartbeat renews, while it is asked stays reserved.
Optional resolveAsked by SqlSpendMeter.reconcile for each expired reservation, in place of resolveUnknown and
unknownAfterLease: consumed, released, or deferred until retryAt with its evidence, which stays reserved and
counted. A resolver that throws defers the reservation for one lease; it never falls through to a default outcome.
An answer is written only to the attempt it was asked about and only while that attempt's lease is still out at the
pass's now, so an operation released and retried while it is asked keeps the retry reserved under its own lease,
and a lease a heartbeat renewed, or a deferral another pass made to a next check after now, stands meanwhile.
Optional onTold of each statement that failed while SqlSpendMeter.ensureSchema brought tables that exist up to the
meter's indexes, with the statement and the error the store threw: the CREATE INDEX of an index the tables lack
(refused, for example, to a role that does not own them, or stopped by a lock or statement timeout), or the read of
the catalogue before them. Such a failure is not fatal: the indexes speed the meter's reads and change none of its
answers, so the meter uses the tables as they are. An error the callback throws is dropped. Without a callback,
nothing is reported.
Optional windowA rolling window in milliseconds. The allowance then holds the units consumed in the windowMs before each
reservation and every unit still reserved, counted from the reservations themselves under the account's row lock,
and every row of the account carries the period window. A consumed unit has left the window once more than
windowMs have passed since its reservation; one still reserved counts whatever its age, until it settles; a
released one never counts.
Optional leaseHow long a reservation lives without a heartbeat. Default 45 seconds.
Optional maxReservations an operation may take in all, its retries after a release included. Default 3.
Optional retryOptional unknownHow an expired reservation settles when the product cannot tell. Default release: the person is not charged for a turn nobody saw finish.
Optional requireRefuse a store that several processes cannot share (no transactions, no persistence or no concurrent access): a SQLite file per process would give every instance an allowance of its own. Default true; tests pass false.
Optional ensureCreate the tables when they are missing, and on tables that exist the indexes they lack (see SqlSpendMeter.ensureSchema). Default true. With false the meter runs no DDL: the product's own migrations make the tables and their indexes.
Optional tableThe start of the two tables' names: <prefix>_meter and <prefix>_reservations, their indexes named after them
(idx_<prefix>_reservations_*). Default agentos_spend, the names SPEND_METER_DDL makes, whose indexes
are idx_spend_reservations_*. Meters with different rules share one database each under a prefix of its own, so
one's count and one's purge never reach another's rows; meters under one prefix share its tables.
A lower-case letter, then at most 37 lower-case letters, digits or underscores, and not spend, whose index names
are the default prefix's. At 38 characters the longest names the meter gives, idx_<prefix>_reservations_account
and idx_<prefix>_reservations_settled, take the 63 bytes Postgres keeps of an identifier. The constructor checks
the prefix before any statement is built and throws on any other value, so nothing unchecked reaches the SQL text.
spendMeterDdl makes the tables for a prefix.
The account's allowance for a period, in units. Read at every reservation, so a plan change applies at the next turn.