Repository: redis/redis-py
File: redis/backoff.py (Python)

Code before:
        return temp + random.uniform(0, temp)


class DecorrelatedJitterBackoff(AbstractBackoff):
    """Decorrelated jitter backoff upon failure"""

    def __init__(self, cap: float = DEFAULT_CAP, base: float = DEFAULT_BASE) -> None:
        """
        `cap`: maximum backoff time in seconds
        `base`: base backoff time in seconds
        """
        self._cap = cap
        self._base = base
        self._previous_backoff = 0

    def __hash__(self) -> int:
        return hash((self._base, self._cap))

    def __eq__(self, other) -> bool:
        if not isinstance(other, DecorrelatedJitterBackoff):
            return NotImplemented

        return (
            self._base == other._base
            and self._cap == other._cap
            and self._previous_backoff == other._previous_backoff
        )

    def reset(self) -> None:
        self._previous_backoff = 0

    def compute(self, failures: int) -> float:
        max_backoff = max(self._base, self._previous_backoff * 3)
        temp = random.uniform(self._base, max_backoff)
        self._previous_backoff = min(self._cap, temp)
        return self._previous_backoff


class ExponentialWithJitterBackoff(AbstractBackoff):
    """Exponential backoff upon failure, with jitter"""

    def __init__(self, cap: float = DEFAULT_CAP, base: float = DEFAULT_BASE) -> None:
        """
        `cap`: maximum backoff time in seconds
        `base`: base backoff time in seconds
        """
        self._cap = cap
        self._base = base

    def __hash__(self) -> int:
        return hash((self._base, self._cap))

Review comment (suggestion):
I think that you should not compare the _previous_backoff fields- they represent the progress/state of the objects, not the configuration. For example, it is also not included in the hash of the object.

Code after:
        return temp + random.uniform(0, temp)


class DecorrelatedJitterBackoff(AbstractBackoff):
    """Decorrelated jitter backoff upon failure"""

    def __init__(self, cap: float = DEFAULT_CAP, base: float = DEFAULT_BASE) -> None:
        """
        `cap`: maximum backoff time in seconds
        `base`: base backoff time in seconds
        """
        self._cap = cap
        self._base = base
        self._previous_backoff = 0

    def __hash__(self) -> int:
        return hash((self._base, self._cap))

    def __eq__(self, other) -> bool:
        if not isinstance(other, DecorrelatedJitterBackoff):
            return NotImplemented

        return self._base == other._base and self._cap == other._cap

    def reset(self) -> None:
        self._previous_backoff = 0

    def compute(self, failures: int) -> float:
        max_backoff = max(self._base, self._previous_backoff * 3)
        temp = random.uniform(self._base, max_backoff)
        self._previous_backoff = min(self._cap, temp)
        return self._previous_backoff


class ExponentialWithJitterBackoff(AbstractBackoff):
    """Exponential backoff upon failure, with jitter"""

    def __init__(self, cap: float = DEFAULT_CAP, base: float = DEFAULT_BASE) -> None:
        """
        `cap`: maximum backoff time in seconds
        `base`: base backoff time in seconds
        """
        self._cap = cap
        self._base = base

    def __hash__(self) -> int:
        return hash((self._base, self._cap))

    def __eq__(self, other) -> bool:
        if not isinstance(other, EqualJitterBackoff):
            return NotImplemented