cunla / fakeredis-py

Implementation of Redis in python without having a Redis server running. Fully compatible with using redis-py.
https://fakeredis.moransoftware.ca/
BSD 3-Clause "New" or "Revised" License
281 stars 47 forks source link

Using a blocking XREAD on an empty stream returns a list instead of blocking #274

Closed liavt closed 8 months ago

liavt commented 8 months ago

Describe the bug When using xread on an empty or non-existant stream with a blocking argument, the function incorrectly returns an empty list instead of blocking.

This is a regression of behavior from the real Redis client.

The source of the bug seems to be in _xread in streammixins.py. If the stream is empty, the function will return res which is an empty list.

When we call xread with a blocking argument, it wraps the function _xread with _blocking from _basefakesocket.py. Since the _xread returns list() instead of None, the blocking wrapper will not retry, as it only yields if the function returns a None.

Having _xread return None in the case of an empty stream could probably fix this issue, but I haven't verified if this doesn't create a regression elsewhere.

To Reproduce Step to reproduce the behavior:

client.xread(streams={"empty-stream": 0}, count=1, block=0)

In fakeredis, this code immediately returns an empty list. The same is also true for the async version.

Expected behavior The same line of code in redis-py yields forever until an event is added to the stream, and returns it.

This is the proper behavior since count is 1 and we specified for it to block infinitely. It should never return a result without exactly one event.

Desktop:

cunla commented 8 months ago

Nice catch. Writing a test for this use case would require threads... I will try to fix it this weekend.