To ensure correctness at scale, FRAGMENT's consistency mode lets you build guardrails without sacrificing performance.
You can configure consistency within your Schema to make granular tradeoffs between throughput and consistency.
You can configure the consistency of the Ledger Entries list query in your Ledger. To do this, set consistencyConfig
at the top level of your Schema:
entries: eventual
for Ledgers that require high throughput but can tolerate a stale entry listentries: strong
for Ledgers that have lower throughput but require strong consistency, such as those powering reconcilation dashboards{
"consistencyConfig": {
"entries": "strong"
},
"chartOfAccounts": [...]
}
By default, all Ledgers use eventual
consistency.
You can configure the consistency of balances, as well as the Ledger Lines list query, in your Ledger Account.
To configure an account's balance consistency, set consistencyConfig.ownBalanceUpdates
within a Ledger Account's definition:
ownBalanceUpdates: eventual
for Ledger Accounts that require high throughput but can tolerate stale balances, such as those used for reportingownBalanceUpdates: strong
for Ledger Accounts that have lower throughput but require strong consistency, such as those used to authorize transactionsSimilarly, to configure the consistency of an account's lines, set consistencyConfig.lines
:
lines: eventual
for Ledger Accounts that require high throughput but can tolerate a stale line listlines: strong
for Ledger Accounts that have lower throughput but require strong consistency, such as those powering transaction histories displayed to end users{
"accounts": [
{
"key": "user-balance",
"template": true,
"type": "asset",
"consistencyConfig": {
"ownBalanceUpdates": "strong",
"lines": "eventual"
}
}
]
}
By default, all Ledger Accounts use eventual
for both properties.
For low-throughput applications, setting all Ledger Accounts as strong
may make implementation easier. To do this, set defaultConsistencyConfig
on chartOfAccounts
:
{
"chartOfAccounts": {
"defaultConsistencyConfig": {
"ownBalanceUpdates": "strong",
"lines": "strong"
},
"accounts": [...]
}
}
Strongly consistent Ledger Accounts generally won't have children, but in all cases child Ledger Accounts inherit the parent's consistencyConfig
setting.
To query a strongly consistent ownBalance
, set consistencyMode
to strong
when querying the Ledger Account:
query GetOwnBalances(
$ledgerAccount: LedgerAccountMatchInput!
) {
ledgerAccount(ledgerAccount: $ledgerAccount) {
ownBalance(consistencyMode: strong)
ownBalances(consistencyMode: strong) {
nodes {
amount
currency {
code
}
}
}
}
}
By default, balance queries on all Ledger Accounts are eventually consistent.
Restrictions:
ownBalance
supports strongly consistent reads; balance
and childBalance
support only eventually consistent readsat
with consistencyMode
to query strongly consistent historical balancesEntry conditions are rules defined in your Schema to manage concurrency and enforce correctness within your Ledger.
Conditions are evaluated when a Ledger Entry is posted. If a condition is not met, the Ledger Entry is not posted and the mutation returns a BadRequestError
with code conditional_request_failed
.
Use precondition
when your application reads a balance and needs to guarantee that it hasn't changed before posting the Ledger Entry.
{
"type": "pay-employee",
"lines": [...],
"conditions": [
{
"account": {
"path": "bank-account"
},
"precondition": {
"ownBalance": {
"eq": "{{current_balance}}"
}
}
}
]
}
Use postcondition
to guarantee that a write never puts a Ledger Account's balance in an undesirable state.
{
"type": "pay-employee",
"lines": [...],
"conditions": [
{
"account": {
"path": "bank-account"
},
"postcondition": {
"ownBalance": {
"gte": "0"
}
}
}
]
}
Restrictions:
ownBalance
, which changes only for Ledger Accounts directly posted to in the Ledger Entry.consistencyConfig.ownBalanceUpdates
set to strong
You can configure an account to have a strongly-consistent ownBalance for specific group keys.
To do this, use the consistencyConfig.groups
configuration in the Schema.
{
"accounts": [
{
"key": "user-balance",
"template": true,
"type": "asset",
"consistencyConfig": {
"groups": [
{
"key": "invoice_id",
"ownBalanceUpdates": "strong"
}
]
}
}
]
}
See Group Ledger Entries for more information about how to use Ledger Entry Groups.
To query a strongly consistent Ledger Entry Group balance, set consistencyMode
to strong
or use_account
when querying the group's balances.
query ListLedgerEntryGroupBalances(
$ledger: LedgerMatchInput!
$groupKey: SafeString!
$groupValue: SafeString!
$consistencyMode: ReadBalanceConsistencyMode
) {
ledgerEntryGroup(ledgerEntryGroup: {
ledger: $ledger,
key: $groupKey,
value: $groupValue,
}) {
balances {
nodes {
account {
path
}
ownBalance(consistencyMode: $consistencyMode)
}
}
}
}
By default, Ledger Entry Group balances are eventually consistent. Like other consistency options, enabling strong consistency will reduce the maximum throughput of an account.
Restrictions: