K Configure Consistency#

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.

a. Ledger Configuration

#

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:

  • Use entries: eventual for Ledgers that require high throughput but can tolerate a stale entry list
  • Use entries: strong for Ledgers that have lower throughput but require strong consistency, such as those powering reconcilation dashboards
Configuring consistency
{
  "consistencyConfig": {
    "entries": "strong"
  },
  "chartOfAccounts": [...]
}

By default, all Ledgers use eventual consistency.

b. Ledger Account Configuration

#

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:

  • Use ownBalanceUpdates: eventual for Ledger Accounts that require high throughput but can tolerate stale balances, such as those used for reporting
  • Use ownBalanceUpdates: strong for Ledger Accounts that have lower throughput but require strong consistency, such as those used to authorize transactions

Similarly, to configure the consistency of an account's lines, set consistencyConfig.lines:

  • Use lines: eventual for Ledger Accounts that require high throughput but can tolerate a stale line list
  • Use lines: strong for Ledger Accounts that have lower throughput but require strong consistency, such as those powering transaction histories displayed to end users
Configuring consistency
{
  "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:

Configuring default consistency
{
  "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.

c. Balance queries

#

To query a strongly consistent ownBalance, set consistencyMode to strong when querying the Ledger Account:

Setting consistency on ownBalance reads
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:

  • Only ownBalance supports strongly consistent reads; balance and childBalance support only eventually consistent reads
  • Querying a strongly consistent balance on an eventually consistent Ledger Account throws a GraphQL error
  • You cannot combine at with consistencyMode to query strongly consistent historical balances

d. Entry conditions

#

Entry 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.

Using precondition

{
  "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.

Using postcondition

{
  "type": "pay-employee",
  "lines": [...],
  "conditions": [
    {
      "account": {
        "path": "bank-account"
      },
      "postcondition": {
        "ownBalance": {
          "gte": "0"
        }
      }
    }
  ]
}

Restrictions:

  • Entry conditions apply to ownBalance, which changes only for Ledger Accounts directly posted to in the Ledger Entry.
  • Ledger Accounts referenced in Entry conditions must have consistencyConfig.ownBalanceUpdates set to strong
  • Linked Ledger Accounts do not support Entry conditions

e. Consistent Groups

#

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.

Ledger Entry Group balance consistency
{
  "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.

f. Query Consistent Groups

#

To query a strongly consistent Ledger Entry Group balance, set consistencyMode to strong or use_account when querying the group's balances.

Setting consistency on group ownBalance reads
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:

  • Ledger Entry Group balances cannot be used for Entry conditions.
  • Querying a strongly consistent Ledger Entry Group balance without configuring strong group consistency for that Ledger Account throws a GraphQL error.