Skip to content

Intermittent errors with AsyncScript when using async RedisCluster #3935

@alisaifee

Description

@alisaifee

Problem

Using redis cluster (async) with redis-py version 7.1.0 results in intermittent NoScript, RedisClusterException or IndexError errors when executing an AsyncScript. These errors are only possible if the cluster client is not initialized on first access (i.e. not created and initialized immediately with await redis.asyncio.RedisCluster.from_url(...)) and there are sufficient concurrent calls to the AsyncScript.

A minimal reproduction:

import asyncio
import random

import redis


async def test_script(client):
    script = client.register_script("return KEYS[1]")
    random_key = str(random.randint(0, 100))
    assert await script([random_key]) == random_key


async def run():
    client = redis.asyncio.RedisCluster.from_url(
        "redis://localhost:7001", decode_responses=True
    )
    await client.script_flush()
    await client.aclose()

    new_client = redis.asyncio.RedisCluster.from_url(
        "redis://localhost:7001", decode_responses=True
    )

    await asyncio.gather(*(test_script(new_client) for _ in range(1024)))
    await new_client.aclose()


asyncio.run(run())

Noted exceptions:

redis.exceptions.NoScriptError: No matching script. Please use EVAL.
Traceback (most recent call last):
  File "/tmp/sandbox/cluster_script.py", line 28, in <module>
    asyncio.run(run())
  File "~/.local/share/uv/python/cpython-3.10.18-macos-x86_64-none/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "~/.local/share/uv/python/cpython-3.10.18-macos-x86_64-none/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
    return future.result()
  File "/tmp/sandbox/cluster_script.py", line 24, in run
    await asyncio.gather(*(test_script(new_client) for _ in range(100)))
  File "/tmp/sandbox/cluster_script.py", line 10, in test_script
    assert await script([random_key]) == random_key
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/commands/core.py", line 6025, in __call__
    return await client.evalsha(self.sha, len(keys), *args)
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 935, in execute_command
    raise e
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 902, in execute_command
    ret = await self._execute_command(target_nodes[0], *args, **kwargs)
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 964, in _execute_command
    return await target_node.execute_command(*args, **kwargs)
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 1307, in execute_command
    return await self.parse_response(connection, args[0], **kwargs)
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 1280, in parse_response
    response = await connection.read_response()
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/connection.py", line 635, in read_response
    raise response from None
redis.exceptions.NoScriptError: No matching script. Please use EVAL.
IndexError: list index out of range
Traceback (most recent call last):
  File "/tmp/sandbox/cluster_script.py", line 28, in <module>
    asyncio.run(run())
  File "~/.local/share/uv/python/cpython-3.10.18-macos-x86_64-none/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "~/.local/share/uv/python/cpython-3.10.18-macos-x86_64-none/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
    return future.result()
  File "/tmp/sandbox/cluster_script.py", line 24, in run
    await asyncio.gather(*(test_script(new_client) for _ in range(100)))
  File "/tmp/sandbox/cluster_script.py", line 10, in test_script
    assert await script([random_key]) == random_key
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/commands/core.py", line 6019, in __call__
    return await client.evalsha(self.sha, len(keys), *args)
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 935, in execute_command
    raise e
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 890, in execute_command
    target_nodes = await self._determine_nodes(
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 737, in _determine_nodes
    nodes = policy_callback(command)
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 444, in <lambda>
    self.get_random_primary_or_all_nodes(command_name)
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 661, in get_random_primary_or_all_nodes
    return self.get_random_primary_node()
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 667, in get_random_primary_node
    return random.choice(self.get_primaries())
  File "~/.local/share/uv/python/cpython-3.10.18-macos-x86_64-none/lib/python3.10/random.py", line 378, in choice
    return seq[self._randbelow(len(seq))]
IndexError: list index out of range

redis.exceptions.RedisClusterException: No targets were found to execute ('SCRIPT LOAD', 'return KEYS[1]') command on
Traceback (most recent call last):
  File "/tmp/sandbox/cluster_script.py", line 28, in <module>
    asyncio.run(run())
  File "~/.local/share/uv/python/cpython-3.10.18-macos-x86_64-none/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "~/.local/share/uv/python/cpython-3.10.18-macos-x86_64-none/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
    return future.result()
  File "/tmp/sandbox/cluster_script.py", line 24, in run
    await asyncio.gather(*(test_script(new_client) for _ in range(100)))
  File "/tmp/sandbox/cluster_script.py", line 10, in test_script
    assert await script([random_key]) == random_key
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/commands/core.py", line 6024, in __call__
    self.sha = await client.script_load(self.script)
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 935, in execute_command
    raise e
  File "/tmp/sandbox/.venv/lib/python3.10/site-packages/redis/asyncio/cluster.py", line 896, in execute_command
    raise RedisClusterException(
redis.exceptions.RedisClusterException: No targets were found to execute ('SCRIPT LOAD', 'return KEYS[1]') command on

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