Skip to content

Commit 360c212

Browse files
authored
Merge pull request #1 from andymccurdy/master
sync with origin
2 parents 20fc04e + 4b663cb commit 360c212

File tree

3 files changed

+63
-5
lines changed

3 files changed

+63
-5
lines changed

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ application.
444444
>>> r.publish('my-channel')
445445
1
446446
>>> p.get_message()
447-
{'channel': 'my-channel', data': 'my data', 'pattern': None, 'type': 'message'}
447+
{'channel': 'my-channel', 'data': 'my data', 'pattern': None, 'type': 'message'}
448448
449449
There are three different strategies for reading messages.
450450

redis/_compat.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,64 @@
11
"""Internal module for Python 2 backwards compatibility."""
22
import sys
33

4+
# For Python older than 3.5, retry EINTR.
5+
if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and
6+
sys.version_info[1] < 5):
7+
# Adapted from https://bugs.python.org/review/23863/patch/14532/54418
8+
import socket
9+
import time
10+
import errno
11+
12+
# Wrapper for handling interruptable system calls.
13+
def _retryable_call(s, func, *args, **kwargs):
14+
# Some modules (SSL) use the _fileobject wrapper directly and
15+
# implement a smaller portion of the socket interface, thus we
16+
# need to let them continue to do so.
17+
timeout, deadline = None, 0.0
18+
attempted = False
19+
try:
20+
timeout = s.gettimeout()
21+
except AttributeError:
22+
pass
23+
24+
if timeout:
25+
deadline = time.time() + timeout
26+
27+
try:
28+
while True:
29+
if attempted and timeout:
30+
now = time.time()
31+
if now >= deadline:
32+
raise socket.error(errno.EWOULDBLOCK, "timed out")
33+
else:
34+
# Overwrite the timeout on the socket object
35+
# to take into account elapsed time.
36+
s.settimeout(deadline - now)
37+
try:
38+
attempted = True
39+
return func(*args, **kwargs)
40+
except socket.error as e:
41+
if e.args[0] == errno.EINTR:
42+
continue
43+
raise
44+
finally:
45+
# Set the existing timeout back for future
46+
# calls.
47+
if timeout:
48+
s.settimeout(timeout)
49+
50+
def recv(sock, *args, **kwargs):
51+
return _retryable_call(sock, sock.recv, *args, **kwargs)
52+
53+
def recv_into(sock, *args, **kwargs):
54+
return _retryable_call(sock, sock.recv_into, *args, **kwargs)
55+
56+
else: # Python 3.5 and above automatically retry EINTR
57+
def recv(sock, *args, **kwargs):
58+
return sock.recv(*args, **kwargs)
59+
60+
def recv_into(sock, *args, **kwargs):
61+
return sock.recv_into(*args, **kwargs)
462

563
if sys.version_info[0] < 3:
664
from urllib import unquote

redis/connection.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from redis._compat import (b, xrange, imap, byte_to_chr, unicode, bytes, long,
1818
BytesIO, nativestr, basestring, iteritems,
1919
LifoQueue, Empty, Full, urlparse, parse_qs,
20-
unquote)
20+
recv, recv_into, unquote)
2121
from redis.exceptions import (
2222
RedisError,
2323
ConnectionError,
@@ -123,7 +123,7 @@ def _read_from_socket(self, length=None):
123123

124124
try:
125125
while True:
126-
data = self._sock.recv(socket_read_size)
126+
data = recv(self._sock, socket_read_size)
127127
# an empty string indicates the server shutdown the socket
128128
if isinstance(data, bytes) and len(data) == 0:
129129
raise socket.error(SERVER_CLOSED_CONNECTION_ERROR)
@@ -341,11 +341,11 @@ def read_response(self):
341341
while response is False:
342342
try:
343343
if HIREDIS_USE_BYTE_BUFFER:
344-
bufflen = self._sock.recv_into(self._buffer)
344+
bufflen = recv_into(self._sock, self._buffer)
345345
if bufflen == 0:
346346
raise socket.error(SERVER_CLOSED_CONNECTION_ERROR)
347347
else:
348-
buffer = self._sock.recv(socket_read_size)
348+
buffer = recv(self._sock, socket_read_size)
349349
# an empty string indicates the server shutdown the socket
350350
if not isinstance(buffer, bytes) or len(buffer) == 0:
351351
raise socket.error(SERVER_CLOSED_CONNECTION_ERROR)

0 commit comments

Comments
 (0)