rqlite 8.38.0 returns the Raft index associated with a request
An opt-in response field carries Raft indexes through local execution and forwarding. It identifies a replicated position without replacing SQL result handling or read-consistency policy.
A successful database response often loses the replication position that produced it. rqlite 8.38.0, released on 18 June, makes that position available through an optional raft_index response field. The work includes carrying the index through inter-node forwarding, so the HTTP entry node does not have to be the node that executes the request.
I like rqlite's decision to expose consistency choices at the request level. An application sometimes needs information about a specific operation rather than another deployment-wide mode. Returning its associated index adds a useful piece of evidence, provided the client keeps the meaning narrower than a complete account of every replica's progress.
The response field is opt-in
PR #2114 adds a query-parameter check for raft_index. The check tests for the key's presence. In the execute and unified request handlers, the response receives the returned index only when that parameter is present.
The companion PR #2113 changes the response field's JSON annotation to raft_index,omitempty. Those two changes work together. The handler decides whether to assign the value, and JSON serialization omits a zero value.
For an already existing example table, a request can ask for the index with the following HTTP invocation. The endpoint and payload illustrate the execute handler changed by the patch.
curl -X POST 'http://localhost:4001/db/execute?raft_index' \
-H 'Content-Type: application/json' \
-d '["INSERT INTO example(id) VALUES(1)"]'
The returned SQL results remain in the ordinary results array. A nonzero index can appear alongside them as a top-level field. The option does not replace those results, and a client still needs to inspect the statement-level outcome.
Presence-based selection also means that the query key is the important input. The implementation does not read a textual true or false value to decide whether the caller wants the field. Supplying the key explicitly is the clearest way to express the request.
The index must survive forwarding
Inter-node changes are a substantial part of the feature. The cluster client methods for execution and unified requests now return an index in addition to results and an error. Protobuf response messages gain a field that carries that value between nodes.
On the service side, successful execution copies the database results and assigns the returned index into the protocol response. On the receiving side, the client unmarshals the message and returns that index to its caller. The HTTP handler can therefore populate its response after forwarding to the leader.
Without that propagation, a response generated by the entry node could omit information that the executing node knew. Clients would observe different metadata depending on which node received the HTTP request. The patch removes that particular dependency on routing.
The diff also shows an intermediate implementation discarding the forwarded index and setting it to zero. The final forwarding change replaces that behavior with actual propagation. This is why describing the release from an early development commit would miss part of its delivered behavior.
The forwarding tests check that remote execution returns a nonzero index. They exercise the cluster client against a running node, beyond merely checking that a new protobuf field compiles. That test addresses the information path the feature depends on.
An index is not a row identifier
The store tests added in PR #2113 create a table and execute a subsequent insert. They require the second returned index to exceed the first. The assertion concerns ordering of associated Raft operations, rather than assigning a number to each changed row.
The same test group examines unified requests. A read-only request at NONE consistency returns zero. A later strong read returns a nonzero index greater than the preceding write's index. These cases demonstrate that the returned value depends on the request's execution path.
That behavior prevents treating every response as a sample of the same progress counter. A zero result from a read path does not establish that the database has applied no writes. In the HTTP response, the zero value is also subject to omission, so absence requires interpretation in the context of the request.
Similarly, an insert's index does not replace its affected-row count or any generated identifier. Those describe SQL execution. The index describes the associated replication position. The response carries both kinds of information because they answer different application questions.
Statement failures still require their own handling
The forwarding tests include requests that refer to a missing table. A test comment explains why those cases avoid meaningful index assertions. SQLite can classify statements causing errors as read-write, so the relation between an index and a useful application mutation is not automatic.
This is a practical reason to keep SQL results attached to any recorded index. A client that stores only the numeric metadata loses whether its intended statement succeeded. The new field adds context to the existing response contract instead of collapsing all outcomes into a progress number.
The option also does not itself add a waiting policy to a subsequent read. The patch returns metadata in responses. Inferring a guarantee for a later read requires examining that read's consistency behavior and how the application uses the recorded position.
My preference is for that explicitness. A number can help correlate a write with replicated progress without silently changing all reads. Applications can retain the metadata where it is useful and continue to choose their read semantics separately.
The API change has a defined scope
The release changelog records exposure of indexes through store execution and unified requests, followed by HTTP response support. It also includes lower-level change-data-capture work. That development context does not make this release's index field a complete change-feed API.
The concrete addition is an optional nonzero Raft position in applicable responses, including forwarded execution. For a client, the useful record combines the originating request, its SQL outcome, and the index that the server returned. Keeping those facts together preserves the distinction between what the application asked to change and where the associated operation occurred in replication.