Skip to content

rvl index listall fails on Redis Cluster: FT._LIST is sent without a target node #847

Open

Description

@limjoobin

Summary

Against a Redis Cluster, rvl index listall exits with status 1 and prints:

No way to dispatch this command to Redis Cluster. Missing key.
You can execute the command by specifying target nodes.
Command: ('FT._LIST',)

Other rvl index subcommands work against the same cluster. rvl index info -i <name>, for example, goes through SearchIndex. listall is the only one that bypasses it.

Reproduction

Start a Redis Cluster with the Search module (Redis 8.x).
Run:

rvl index listall --url "redis://127.0.0.1:7201?cluster=true"

The --json variant fails the same way, with nothing on stdout.

The CLI effectively does this:

from redis.cluster import RedisCluster

client = RedisCluster.from_url("redis://127.0.0.1:7201")
client.execute_command("FT._LIST")  # RedisClusterException: Missing key

# Sending it to one node works and returns the full index list:
client.execute_command("FT._LIST", target_nodes=client.get_default_node())
# [b'my_index']

Expected behaviour: the command prints the indexes in the cluster, as it does against a standalone Redis.

Actual behaviour: it exits with status 1 and prints the RedisClusterException above to stderr.

Cause

Index.listall() in redisvl/cli/index.py opens its own connection and sends the command directly:

conn = RedisConnectionFactory.get_redis_connection(redis_url=redis_url)
indices = convert_bytes(conn.execute_command("FT._LIST"))

FT._LIST takes no key. redis-py 7.x and 8.x route keyless search commands using a static policy table (redis/commands/policies.py), and _list isn’t in that table’s ft section. So redis-py falls back to slot routing by key, finds no key, and raises. Sync SearchIndex.listall() behaves the same way on main: it worked on redis-py 6.4 and failed on 7.4 and 8.1.

Related: #795 fixes SearchIndex.listall() and AsyncSearchIndex.listall() on a cluster by sending FT._LIST to client.get_default_node(). The CLI doesn’t call either method, so it stays broken after #795 merges.

Suggested fix

Have the CLI list indexes through SearchIndex.listall(), so it uses the same cluster routing. There’s already a helper that does this: redisvl.migration.utils.list_indexes() builds a placeholder SearchIndex and calls listall(). The CLI can call it, or the helper can move to a neutral module such as redisvl/redis/utils.py so cli/index.py doesn’t import from migration/.

Ordering: this should land after #795. The change doesn’t touch #795’s files, but the CLI only works on a cluster once #795’s listall() routing is on main.

Tests: add a unit test that runs rvl index listall (with and without --json) and checks that it calls SearchIndex.listall() and prints the result.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions