Skip to content

Conversation

a-TODO-rov
Copy link
Contributor

TL;DR: Make FT.AGGREGATE … WITHCURSOR sticky to the shard that created it by carrying the routing token (nodeId) in the AggregationReply and routing FT.CURSOR READ/DEL accordingly. No writer changes.

What changed

  • AggregationReply<K,V>

    • Added @Nullable String nodeId + getNodeId(); package-private setNodeId(...).
    • Not included in equals/hashCode.
  • API (all @Experimental)

    • Cursor ops now consume the reply:

      • ftCursorread(AggregationReply<K,V> reply, int count)
      • ftCursorread(AggregationReply<K,V> reply)
      • ftCursordel (AggregationReply<K,V> reply)
    • Removed/adapted old (index, cursorId) variants.

  • Cluster behavior

    • After decoding FT.AGGREGATE, if cursorId > 0, stamp reply.setNodeId(executedNode.getNodeId()).
    • ftCursorread/ftCursordel resolve reply.nodeId → endpoint via Partitions and dispatch to that node.
  • Single node / missing nodeId

    • Falls back to existing single-node path.

Migration note

  • Breaking only for experimental cursor methods: pass the original AggregationReply instead of (index, cursorId).

What's next

Stage 2: read-write load-balancing for keyless commands, including FT.SEARCH/FT.AGGREGATE.

@a-TODO-rov a-TODO-rov requested review from uglide and tishun August 22, 2025 14:28
Copy link
Collaborator

@uglide uglide left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tishun let me know if you agree on the API change I suggest

@@ -1713,17 +1713,26 @@ public RedisFuture<AggregationReply<K, V>> ftAggregate(K index, V query) {
}

@Override
public RedisFuture<AggregationReply<K, V>> ftCursorread(K index, long cursorId, int count) {
return dispatch(searchCommandBuilder.ftCursorread(index, cursorId, count));
public RedisFuture<AggregationReply<K, V>> ftCursorread(K index, AggregationReply<K, V> aggregateReply, int count) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One reason to iterate over the aggregated result with the cursor is that the reply is too big, contains too many results, etc. Using AggregationReply as an argument to ftCursorread defeats the original purpose. A much cleaner approach would be to introduce an abstraction for Cursor that encapsulates the cursorId and nodeId and pass it to the ftCursor commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants