question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

redis-py is not compatible with select.select()

See original GitHub issue

In a project involving websockets and redis, select.select() is being used to be notified when either a websocket or redis pub/sub has data ready for reading. For it to work at all, we have to peek under the covers of redis-py a bit to get at the socket’s file descriptor and receive the messages:

r = redis.StrictRedis()
pubsub = r.pubsub()

# subscribe to a few channels...

fd = pubsub.connection._sock.fileno()
while True:
    ready = select.select([fd], [], [])
    response = pubsub.parse_response()
    # do something with response

This generally works pretty well. However, we’ve discovered that when publishing multiple messages to subscribed channels in quick succession, select() tends to only return once for the first message, but not for subsequent messages. After a lot of digging, it turns out this is due to redis-py using buffered reads on its pub/sub socket. In particular, redis.connection.PythonParser.read uses readline, which is a buffered read operation. Several messages are read off the socket by the single call to readline, but all except the first message are buffered until the next time readline (or another read operation) is called. Due to this buffereing, select() will not fire again since there isn’t any additional data to be read off the socket.

It would be really powerful if redis-py could be made compatible with select.select(). As a proof of concept, I addressed the issue by monkey patching PythonParser’s read method to do unbuffered reads as shown below. This is clearly less efficient than doing buffered reads, but it seems something along these lines would be needed for select() compatibility.

# excerpt from redis.connection.PythonParser.read

...

# no length, read a full line
# readline is buffered, so #badnewsbears
#return self._fp.readline()[:-2]

# let's do it unbuffered instead!
buf = BytesIO()
byte = None
while byte != '\n':
    byte = self._fp.read(1)
    buf.write(byte)
buf.seek(0)
return buf.read()[:-2]

...

Note that this isn’t a valid solution by itself since hiredis also does buffered reads…

Does anyone have any thoughts on how redis-py could be adapted in a not-so-hacky way to make it play nice with select.select()?

Issue Analytics

  • State:closed
  • Created 10 years ago
  • Comments:21 (12 by maintainers)

github_iconTop GitHub Comments

1reaction
ntkicommented, Apr 23, 2014

Hi all!

Please consider changing from select.select() to select.poll(). If you have a long running app that handles reconnections and all that, the underlying filedescriptor number of the socket can be 1024>= and select could easily crash because of that. (in libhiredis too they changed that between 0.10-0.11)

Br

0reactions
andymccurdycommented, Jun 2, 2014

redis-py 2.10 is out with the new pubsub system.

@ntki I’ve created a separate issue (#486) to track the change of moving from select.select() to something better.

Read more comments on GitHub >

github_iconTop Results From Across the Web

redis-py is not compatible with select.select() #419 - GitHub
In a project involving websockets and redis, select.select() is being used to be notified when either a websocket or redis pub/sub has data ......
Read more >
Welcome to redis-py's documentation! — redis-py dev ...
There are two quick ways to connect to Redis. Assuming you run Redis on localhost:6379 (the default). import redis r = redis.Redis() r.ping()....
Read more >
Redis AUTH command in Python - Stack Overflow
I don't know how to AUTH after making the connection in Python. The following code does not work: import redis r = redis.StrictRedis()...
Read more >
How to Use Redis With Python
Redis creator Salvatore Sanfilippo would probably not love the comparison of a Redis database to a ... The closest thing in Python is...
Read more >
redis 2.10.6 - PyPI
As a result, redis-py does not implement the SELECT command on client instances. If you use multiple Redis databases within the same application, ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found