diff --git a/redis/asyncio/cluster.py b/redis/asyncio/cluster.py index 28fcd3aa23..35ea2e580e 100644 --- a/redis/asyncio/cluster.py +++ b/redis/asyncio/cluster.py @@ -808,10 +808,16 @@ async def _execute_command( # and try again with the new setup await self.aclose() raise - except ClusterDownError: + except (ClusterDownError, SlotNotCoveredError): # ClusterDownError can occur during a failover and to get # self-healed, we will try to reinitialize the cluster layout # and retry executing the command + + # SlotNotCoveredError can occur when the cluster is not fully + # initialized or can be temporary issue. + # We will try to reinitialize the cluster topology + # and retry executing the command + await self.aclose() await asyncio.sleep(0.25) raise diff --git a/redis/cluster.py b/redis/cluster.py index 39b454babe..fc5ffab892 100644 --- a/redis/cluster.py +++ b/redis/cluster.py @@ -410,7 +410,12 @@ class AbstractRedisCluster: list_keys_to_dict(["SCRIPT FLUSH"], lambda command, res: all(res.values())), ) - ERRORS_ALLOW_RETRY = (ConnectionError, TimeoutError, ClusterDownError) + ERRORS_ALLOW_RETRY = ( + ConnectionError, + TimeoutError, + ClusterDownError, + SlotNotCoveredError, + ) def replace_default_node(self, target_node: "ClusterNode" = None) -> None: """Replace the default cluster node. @@ -1239,13 +1244,19 @@ def _execute_command(self, target_node, *args, **kwargs): except AskError as e: redirect_addr = get_node_name(host=e.host, port=e.port) asking = True - except ClusterDownError as e: + except (ClusterDownError, SlotNotCoveredError): # ClusterDownError can occur during a failover and to get # self-healed, we will try to reinitialize the cluster layout # and retry executing the command + + # SlotNotCoveredError can occur when the cluster is not fully + # initialized or can be temporary issue. + # We will try to reinitialize the cluster topology + # and retry executing the command + time.sleep(0.25) self.nodes_manager.initialize() - raise e + raise except ResponseError: raise except Exception as e: