XREAD requests fail to block on empty streams, if the stream actually contained some entries before and the passed last-received-id is smaller than stream's remembered last_id.
Example to reproduce:
XADD mystream * key val 1535560473877-0 XDEL mystream 1535560473877-0 XREAD BLOCK 2000 STREAMS mystream 0 1) 1) "mystream" 2) (empty list or set)
The XREAD returns synchronously with an empty list instead of blocking for 2000ms and returning an empty response.
The responsible check in t_stream.c:xreadCommand:1447 <<< if (streamCompareID(&s->last_id, gt) > 0) { serve_synchronously = 1; } <<< probably assumes, that there must also be entries present, if the stream's last_id is not 0,0. But an additional check for s->length != 0 would also be necessary,
I will also post a small Pull-Request, which worked for me.
Comment From: SaschaRoland
One note to the patch. The patch marks at least the significant lines (and helps me for the moment to avoid full throttle xread-loops in my clients). It's not an entire fix for the blocking issue, since it only fixes the blocking behaviour for empty streams.
If the stream still contains some entries, but none with a larger ID than requested by the last-received-id parameter, then the request is still answered synchronously with an empty result list. E.g.
XADD mystream * key1 val1 => returns ID1 XADD mystream * key2 val2 => returns ID2 XDEL mystream ID2 XREAD BLOCK 2000 STREAMS mystream ID1 => does not block and answers synchronously with empty result list
Comment From: adioanca
I've found a workaround, described here: https://stackoverflow.com/questions/55497990/redis-streams-inconsistent-behavior-of-blocking-xread-after-xdel/55504518
Comment From: yoonghm
Every stream has a timestamp of last entry (last-generated-id) (See xinfo stream mystream). The entry persists even the last message was deleted. It may be too expensive to search the timestamp of previous message as new messages may be still coming it, making the change useless.
Hence we could not rely on the timestamp ID from message retrieved using xrevrange mystream + - count 1.