Repository: redis/redis-py
File: redis/commands/core.py (Python)

Code before:
                )
            pieces.append(b"CLAIM")
            pieces.append(claim_min_idle_time)
            options["claim_min_idle_time"] = claim_min_idle_time
        if not isinstance(streams, dict) or len(streams) == 0:
            raise DataError("XREADGROUP streams must be a non empty dict")
        pieces.append(b"STREAMS")
        pieces.extend(streams.keys())
        pieces.extend(streams.values())
        response = self.execute_command("XREADGROUP", *pieces, **options)

        self._event_dispatcher.dispatch(
            OnStreamMessageReceivedEvent(
                response=response,
                consumer_group=groupname,
                consumer_name=consumername,
            )
        )

        return response

    def xrevrange(
        self,
        name: KeyT,
        max: StreamIdT = "+",
        min: StreamIdT = "-",
        count: Optional[int] = None,
    ) -> ResponseT:
        """
        Read stream values within an interval, in reverse order.

        name: name of the stream

        start: first stream ID. defaults to '+',
               meaning the latest available.

        finish: last stream ID. defaults to '-',
                meaning the earliest available.

        count: if set, only return this many items, beginning with the
               latest available.

        For more information, see https://redis.io/commands/xrevrange
        """
        pieces: list[EncodableT] = [max, min]
        if count is not None:
            if not isinstance(count, int) or count < 1:
                raise DataError("XREVRANGE count must be a positive integer")
            pieces.append(b"COUNT")
            pieces.append(str(count))


Review comment (bug):
The event is dispatched even when the response is None or an empty collection. The XREADGROUP command can return None when using blocking mode with a timeout, or empty list/dict when there are no messages. The ExportStreamingLagMetric listener will fail when trying to iterate over None, and will waste processing time on empty responses. Consider checking if the response is non-empty before dispatching the event.
```suggestion
        if response:
            self._event_dispatcher.dispatch(
                OnStreamMessageReceivedEvent(
                    response=response,
                    consumer_group=groupname,
                    consumer_name=consumername,
                )
            )
```

Code after:
            pieces.append(b"BLOCK")
            pieces.append(str(block))
        if noack:
            pieces.append(b"NOACK")
        if claim_min_idle_time is not None:
            if not isinstance(claim_min_idle_time, int) or claim_min_idle_time < 0:
                raise DataError(
                    "XREADGROUP claim_min_idle_time must be a non-negative integer"
                )
            pieces.append(b"CLAIM")
            pieces.append(claim_min_idle_time)
            options["claim_min_idle_time"] = claim_min_idle_time
        if not isinstance(streams, dict) or len(streams) == 0:
            raise DataError("XREADGROUP streams must be a non empty dict")
        pieces.append(b"STREAMS")
        pieces.extend(streams.keys())
        pieces.extend(streams.values())
        response = self.execute_command("XREADGROUP", *pieces, **options)

        self._event_dispatcher.dispatch(
            OnStreamMessageReceivedEvent(
                response=response,
                consumer_group=groupname,
                consumer_name=consumername,
            )
        )

        return response

    def xrevrange(
        self,
        name: KeyT,
        max: StreamIdT = "+",
        min: StreamIdT = "-",
        count: Optional[int] = None,
    ) -> ResponseT:
        """
        Read stream values within an interval, in reverse order.

        name: name of the stream

        start: first stream ID. defaults to '+',
               meaning the latest available.

        finish: last stream ID. defaults to '-',
                meaning the earliest available.

        count: if set, only return this many items, beginning with the
               latest available.

        For more information, see https://redis.io/commands/xrevrange