rqlite auto reads choose consistency by node role
rqlite 8.25.0 maps auto reads to weak consistency on voters and none on non-voters. The policy simplifies routing while preserving a distinction clients need to understand.
A client that can reach both voting and non-voting database nodes has a policy decision before it executes a read. It can require service through the leader, or it can accept the receiving node's local state. Those choices have different implications for where the request runs. rqlite 8.25.0, released on June 8, adds an auto read-consistency mode that makes this decision using the receiving node's voting role.
The release changelog records the new level through pull request 1796. Its name could suggest a general policy that estimates latency or discovers the strongest available read. In the implementation, a voter selects weak, while a non-voter selects none. That fixed mapping is the useful definition of the feature.
I value rqlite's explicit consistency choices because they let an application decide what each request needs. The automatic mode is useful when the deployment's node roles already express the intended read policy. It reduces client configuration while leaving a concrete rule that an operator can inspect. Understanding that rule is necessary before treating differently placed nodes as interchangeable read targets.
The mapping happens before execution
The store implementation at 8.25.0 handles the new level near the start of its query method. It asks whether the node is a voter. If that lookup fails, the query returns the error. Otherwise, it replaces the automatic level in the request with the selected existing level and continues through the ordinary query logic.
This design reuses established behaviour. The code does not introduce another local database access method for automatic reads. Once the mapping has happened, the weak or none branch decides whether the node can execute the request. The consistency label therefore becomes a short policy selection step before existing checks run.
The HTTP query parameter parser recognises auto explicitly. Its default remains weak in this release. An application opts into the new mapping by specifying it, as in this request for a simple constant expression.
curl --get 'http://localhost:4001/db/query' \
--data-urlencode 'q=SELECT 1' \
--data-urlencode 'level=auto'
Omitting level does not produce the same policy merely because the new mode exists. That difference matters for a client deployed before the upgrade. Its existing requests retain the parser's prior default unless their query parameters change. Availability of an additional level does not itself rewrite application intent.
Voters retain the leader requirement
After a voter maps the request to weak consistency, the store checks its current Raft state. A node that is not the leader returns the not-leader error. The receiving voter does not serve an automatic read from its own local database merely because it participates in elections. Voting membership and current leadership are different properties.
The HTTP query handler provides the next part of that behaviour. In the release's service implementation, a not-leader result enters the existing leader-handling path. The handler can redirect when requested, or it can obtain the leader address and forward the query through the cluster client. The new level therefore works with the routing behaviour already used for leader-dependent reads.
Strong consistency follows a different branch in the store. That branch checks leadership and readiness, serializes the query command, and submits it through Raft. Automatic mode does not select that branch under either outcome of its voter check. Describing auto as automatically requesting the strongest available consistency would give clients a false expectation about coordination.
This distinction also explains why node placement remains relevant. Sending the same automatic request to a voter can cause leader forwarding. Sending it to a non-voter selects the local-read behaviour instead. The choice of destination determines the policy before the request reaches SQLite, even though the URL parameter remains identical.
Non-voters use the local-read policy
For a non-voter, the store maps automatic consistency to none. Before calling the database, the query method applies its stale-read check for that level. Requests can include freshness information, so choosing the local-read policy does not eliminate every possible rejection. The selected level still uses the checks implemented for it.
Request-level transactions also retain their existing treatment. When a local query requests a transaction without going through consensus, the store acquires its query transaction read lock before calling the database. The source comments explain that this blocks database serialization during that query. Automatic selection does not bypass this transaction handling, since it resolves to an existing consistency branch before execution proceeds.
The parameter parser exposes freshness as a duration and freshness_strict as a flag. These are separate from the consistency string. An application can therefore state an automatic routing policy while also carrying the freshness parameters that the resulting local-read branch understands. The exact stale-read calculation belongs to that existing branch, rather than to a new algorithm inside auto.
A useful implication follows from the mapping. Turning a node into a different membership role changes how automatic reads are classified there. The policy belongs partly to deployment configuration, not solely to the request text. That is convenient when non-voters exist to serve local reads, but it is still an architectural choice that clients inherit from their destinations.
My preference is to use explicit levels when a particular operation has a fixed consistency requirement. Automatic mode has a different purpose when the requirement is deliberately tied to node role. Keeping that distinction clear avoids assigning stronger guarantees to a request merely because its configuration is shorter.
The implementation is also straightforward to explain during an operational investigation. First determine the receiving node's voter status. That establishes whether the request becomes weak or none. Leadership then matters for the weak path, while freshness checks can matter for the none path. The feature simplifies the client's selection rule by expressing it through node membership, and the existing query paths still determine how the selected read runs.