Skip to main content

Query Consistency Modes

Background

When querying OpenFGA using Read or any of the query APIs like Check, Expand, ListObjects and ListUsers, you can specify a query consistency parameter that can have one of the following values:

NameDescription
MINIMIZE_LATENCY (default)OpenFGA will serve queries from the cache when possible
HIGHER_CONSISTENCYOpenFGA will skip the cache and query the database directly

If you write a tuple and you immediately make a Check on a relation affected by that tuple using MINIMIZE_LATENCY, the tuple change might not be taken in consideration if OpenFGA serves the result from the cache.

When to use higher consistency

When specifying HIGHER_CONSISTENCY you are trading off consistency for latency and system performance. Always specifying HIGHER_CONSISTENCY will have a significant impact in performance.

If you have a use case where higher consistency is needed, it's recommended that whenever possible, you decide in runtime the consistency level you need. If you are storing a timestamp indicating when a resource was last modified in your database, you can use that to decide the kind of request you do.

For example, if you share document:readme with a user:anne and you update a modified_date field in the document table when that happens, you can write code like the below when calling check("user:anne", "can_view", "document:readme") to avoid paying the price of additional latency when calling the API.

if (date_modified + cache_time_to_live_period > Date.now()) {
const { allowed } = await fgaClient.check(
{ user: "user:anne", relation: "can_view", object: "document:roadmap"}
);
} else {
const { allowed } = await fgaClient.check(
{ user: "user:anne", relation: "can_view", object: "document:roadmap"},
{ consistency: ConsistencyPreference.HigherConsistency }
);
}

Cache expiration

OpenFGA caching is disabled by default. When caching is disabled, all queries will have strong consistency regardless of the consistency mode specified. When caching is enabled, the cache will be used for queries with MINIMIZE_LATENCY consistency mode.

You can use the following parameters to configure OpenFGA's cache:

NameDescription
check-cache-limitConfigures the number of items that will be kept in the in-memory cache used to resolve Check queries (default = 1000)
check-query-cache-enabledEnables in-memory caching of Check subproblems (default = false). For example, if you have a relation define viewer: owner or editor, and the query is Check(user:anne, viewer, doc:1), we'll evaluate the owner relation and the editor relation and cache both results: (user:anne, viewer, doc:1) -> allowed=true and (user:anne, owner, doc:1) -> allowed=true.
check-query-cache-ttlSpecifies the time that items will be kept in the cache of Check subproblems (default = 10s)
check-iterator-cache-enabledEnables in-memory caching of database iterators. Each iterator is the result of a database query, for example, usersets related to a specific object, or objects related to a specific user, up to a certain number of tuples per iterator (default = false)
check-iterator-cache-max-resultsConfigures the number of tuples that will be stored for each database iterator (default = 10000)
check-iterator-cache-ttlSpecifies the time that items will be kept in the cache of database iterators (default = 10s)

Learn how to configure OpenFGA.

Currently, the cache is used by Check and partially in ListObjects. It will be implemented for other query endpoints in the future.

Future work

The Zanzibar paper has a feature called Zookies, which is a consistency token that is returned from Write operation. You can store that token in you resource table, and specify it in subsequent calls to query APIs.

OpenFGA is considering a similar feature in future releases.

Relationship Queries

Comparison Between Check, Read And Expand API Calls.