Skip to content

Commit 15f4d78

Browse files
committed
Avoid an extra "can_read" call and use timeout directly.
1 parent 4c06fa7 commit 15f4d78

File tree

2 files changed

+39
-46
lines changed

2 files changed

+39
-46
lines changed

redis/asyncio/client.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -754,9 +754,8 @@ async def parse_response(self, block: bool = True, timeout: float = 0):
754754

755755
await self.check_health()
756756

757-
if not block and not await self._execute(conn, conn.can_read, timeout=timeout):
758-
return None
759-
response = await self._execute(conn, conn.read_response)
757+
read_timeout = None if block else timeout
758+
response = await self._execute(conn, conn.read_response, timeout=read_timeout)
760759

761760
if conn.health_check_interval and response == self.health_check_response:
762761
# ignore the health check message as user might not expect it

redis/asyncio/connection.py

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import contextlib
23
import copy
34
import enum
45
import errno
@@ -56,6 +57,19 @@
5657
if HIREDIS_AVAILABLE:
5758
import hiredis
5859

60+
if sys.version_info[:2] >= (3, 10):
61+
nullcontext = contextlib.nullcontext()
62+
else:
63+
64+
class NullContext:
65+
async def __aenter__(self):
66+
pass
67+
68+
async def __aexit__(self, *args):
69+
pass
70+
71+
nullcontext = NullContext()
72+
5973
NONBLOCKING_EXCEPTION_ERROR_NUMBERS = {
6074
BlockingIOError: errno.EWOULDBLOCK,
6175
ssl.SSLWantReadError: 2,
@@ -918,55 +932,27 @@ async def can_read(self, timeout: float = 0):
918932
f"Error while reading from {self.host}:{self.port}: {e.args}"
919933
)
920934

921-
async def read_response(self, disable_decoding: bool = False):
922-
"""Read the response from a previously sent command"""
923-
try:
924-
async with self._lock:
925-
if self.socket_timeout:
926-
async with async_timeout.timeout(self.socket_timeout):
927-
response = await self._parser.read_response(
928-
disable_decoding=disable_decoding
929-
)
930-
else:
931-
response = await self._parser.read_response(
932-
disable_decoding=disable_decoding
933-
)
934-
except asyncio.TimeoutError:
935-
await self.disconnect()
936-
raise TimeoutError(f"Timeout reading from {self.host}:{self.port}")
937-
except OSError as e:
938-
await self.disconnect()
939-
raise ConnectionError(
940-
f"Error while reading from {self.host}:{self.port} : {e.args}"
941-
)
942-
except BaseException:
943-
await self.disconnect()
944-
raise
945-
946-
if self.health_check_interval:
947-
if sys.version_info[0:2] == (3, 6):
948-
func = asyncio.get_event_loop
949-
else:
950-
func = asyncio.get_running_loop
951-
self.next_health_check = func().time() + self.health_check_interval
952-
953-
if isinstance(response, ResponseError):
954-
raise response from None
955-
return response
956-
957-
async def read_response_without_lock(self, disable_decoding: bool = False):
935+
async def read_response(
936+
self,
937+
disable_decoding: bool = False,
938+
timeout: Optional[float] = None,
939+
with_lock: bool = True,
940+
):
958941
"""Read the response from a previously sent command"""
942+
read_timeout = timeout if timeout is not None else self.socket_timeout
943+
lock_ctxt = self._lock if with_lock else nullcontext
944+
if not self.is_connected:
945+
await self.connect()
959946
try:
960-
if self.socket_timeout:
961-
async with async_timeout.timeout(self.socket_timeout):
962-
response = await self._parser.read_response(
963-
disable_decoding=disable_decoding
964-
)
965-
else:
947+
async with lock_ctxt, async_timeout.timeout(read_timeout):
966948
response = await self._parser.read_response(
967949
disable_decoding=disable_decoding
968950
)
969951
except asyncio.TimeoutError:
952+
if timeout is not None:
953+
# user requested timeout, return None
954+
return None
955+
# it was a self.socket_timeout error.
970956
await self.disconnect()
971957
raise TimeoutError(f"Timeout reading from {self.host}:{self.port}")
972958
except OSError as e:
@@ -989,6 +975,14 @@ async def read_response_without_lock(self, disable_decoding: bool = False):
989975
raise response from None
990976
return response
991977

978+
async def read_response_without_lock(
979+
self, disable_decoding: bool = False, timeout: Optional[float] = None
980+
):
981+
"""Read the response from a previously sent command"""
982+
return await self.read_response(
983+
disable_decoding=disable_decoding, timeout=timeout, with_lock=False
984+
)
985+
992986
def pack_command(self, *args: EncodableT) -> List[bytes]:
993987
"""Pack a series of arguments into the Redis protocol"""
994988
output = []

0 commit comments

Comments
 (0)