redis-py: Jython/win10 only: Error while reading from socket: (11, 'Resource temporarily unavailable')

Hi ! thank you for your work. Need help on this point if possible 👍

Version: redis-py: 3.5.3

Redis server tested: both windows 10 service (redis v4.0.2.3) and a kali linux (v6.0.6) running virtualbox6

Platform: windows 10 / Python 3.8.2 / jython 2.7.2

Description:

The code below, work as expected with python

import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
r.publish('/foo', 'bar')

But fail with jython

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\jython2.7.2\Lib\site-packages\redis\client.py", line 3098, in publish
    return self.execute_command('PUBLISH', channel, message)
  File "D:\jython2.7.2\Lib\site-packages\redis\client.py", line 898, in execute_command
    conn = self.connection or pool.get_connection(command_name, **options)
  File "D:\jython2.7.2\Lib\site-packages\redis\connection.py", line 1203, in get_connection
    if connection.can_read():
  File "D:\jython2.7.2\Lib\site-packages\redis\connection.py", line 734, in can_read
    return self._parser.can_read(timeout)
  File "D:\jython2.7.2\Lib\site-packages\redis\connection.py", line 321, in can_read
    return self._buffer and self._buffer.can_read(timeout)
  File "D:\jython2.7.2\Lib\site-packages\redis\connection.py", line 229, in can_read
    return bool(self.length) or \
  File "D:\jython2.7.2\Lib\site-packages\redis\connection.py", line 222, in _read_from_socket
    raise ConnectionError("Error while reading from socket: %s" %
redis.exceptions.ConnectionError: Error while reading from socket: (11, 'Resource temporarily unavailable')

Server is up and reachable, using redis-cli or python code, everything is ok, but not the jython code.

Any suggestion ?

Thank you !

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 17 (5 by maintainers)

Most upvoted comments

I managed to reproduce this with Win10 running within VirtualBox with Oracle Java 8 and Jython 2.7.2 installed.

The error is happening in the connection pool’s basic health check. Behind the scenes, the connection is temporarily put into nonblocking mode and a recv() is attempted. If recv() returns any data, the connection is bad (generally it means the connection to the server has been severed) and the connection pool re-establishes the connection.

redis-py has a mapping of known exception types and error numbers that a socket in nonblocking mode will raise when recv() is called. Think of it as an exception whitelist. A healthy connection will raise one of these and that indicates to the connection pool that the socket is in good working order.

On most platforms, BlockingIOError is raised with a errno.EWOULDBLOCK error number. It looks like Jython (at least on Windows) has chosen to use a different exception/error number to indicate that the socket would block. On my Win10 test w/ Java 8 and Jython 2.7.2, calling recv() on a socket in nonblocking mode raises a socket.error with the errno.EAGAIN error number.

The problem here is that socket.error is already in the NONBLOCKING_EXCEPTION_ERROR_NUMBERS dict with the errno.EWOULDBLOCK error number value, and we don’t support multiple error numbers for a single exception type. You can see the error mapping starting here: https://github.com/andymccurdy/redis-py/blob/3.5.3/redis/connection.py#L42. Note that in the Python/Jython 2.x case, BlockingIOError is aliased to socket.error.

Additionally, we’ve stopped supporting Python 2. redis-py 3.5.3 is the last release that will run on Python 2.

The good news is that there’s an easy workaround to fix your problem. Add the following code snippet to your app’s initialization somewhere before trying to use Redis. It only needs to be executed once per interpreter. It adds the Jython exception type and error number to the whitelist. The connection worked for me afterwards.

import errno
import socket
from redis import connection
connection.NONBLOCKING_EXCEPTION_ERROR_NUMBERS[socket.error] = errno.EAGAIN
connection.NONBLOCKING_EXCEPTIONS = tuple(connection.NONBLOCKING_EXCEPTION_ERROR_NUMBERS.keys())

Oh, I must have misunderstood. So your issue only happens when your client is running on Jython for Windows? And it works fine when you run the client on Jython under Linux?