Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
wait.py274 linesDownload Raw Back to tenacity
1# Copyright 2016–2021 Julien Danjou2# Copyright 2016 Joshua Harlow3# Copyright 2013-2014 Ray Holder4#5# Licensed under the Apache License, Version 2.0 (the "License");6# you may not use this file except in compliance with the License.7# You may obtain a copy of the License at8#9# http://www.apache.org/licenses/LICENSE-2.010#11# Unless required by applicable law or agreed to in writing, software12# distributed under the License is distributed on an "AS IS" BASIS,13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14# See the License for the specific language governing permissions and15# limitations under the License.16 17import abc18import random19import typing20 21from tenacity import _utils22 23if typing.TYPE_CHECKING:24    from tenacity import RetryCallState25 26 27class wait_base(abc.ABC):28    """Abstract base class for wait strategies."""29 30    @abc.abstractmethod31    def __call__(self, retry_state: "RetryCallState") -> float:32        pass33 34    def __add__(self, other: "wait_base") -> "wait_combine":35        return wait_combine(self, other)36 37    def __radd__(self, other: "wait_base") -> typing.Union["wait_combine", "wait_base"]:38        # make it possible to use multiple waits with the built-in sum function39        if other == 0:  # type: ignore[comparison-overlap]40            return self41        return self.__add__(other)42 43 44WaitBaseT = typing.Union[45    wait_base, typing.Callable[["RetryCallState"], typing.Union[float, int]]46]47 48 49class wait_fixed(wait_base):50    """Wait strategy that waits a fixed amount of time between each retry."""51 52    def __init__(self, wait: _utils.time_unit_type) -> None:53        self.wait_fixed = _utils.to_seconds(wait)54 55    def __call__(self, retry_state: "RetryCallState") -> float:56        return self.wait_fixed57 58 59class wait_none(wait_fixed):60    """Wait strategy that doesn't wait at all before retrying."""61 62    def __init__(self) -> None:63        super().__init__(0)64 65 66class wait_random(wait_base):67    """Wait strategy that waits a random amount of time between min/max."""68 69    def __init__(70        self, min: _utils.time_unit_type = 0, max: _utils.time_unit_type = 171    ) -> None:  # noqa72        self.wait_random_min = _utils.to_seconds(min)73        self.wait_random_max = _utils.to_seconds(max)74 75    def __call__(self, retry_state: "RetryCallState") -> float:76        return self.wait_random_min + (77            random.random() * (self.wait_random_max - self.wait_random_min)78        )79 80 81class wait_combine(wait_base):82    """Combine several waiting strategies."""83 84    def __init__(self, *strategies: wait_base) -> None:85        self.wait_funcs = strategies86 87    def __call__(self, retry_state: "RetryCallState") -> float:88        return sum(x(retry_state=retry_state) for x in self.wait_funcs)89 90 91class wait_chain(wait_base):92    """Chain two or more waiting strategies.93 94    If all strategies are exhausted, the very last strategy is used95    thereafter.96 97    For example::98 99        @retry(wait=wait_chain(*[wait_fixed(1) for i in range(3)] +100                               [wait_fixed(2) for j in range(5)] +101                               [wait_fixed(5) for k in range(4)]))102        def wait_chained():103            print("Wait 1s for 3 attempts, 2s for 5 attempts and 5s "104                  "thereafter.")105    """106 107    def __init__(self, *strategies: wait_base) -> None:108        self.strategies = strategies109 110    def __call__(self, retry_state: "RetryCallState") -> float:111        wait_func_no = min(max(retry_state.attempt_number, 1), len(self.strategies))112        wait_func = self.strategies[wait_func_no - 1]113        return wait_func(retry_state=retry_state)114 115 116class wait_exception(wait_base):117    """Wait strategy that waits the amount of time returned by the predicate.118 119    The predicate is passed the exception object. Based on the exception, the120    user can decide how much time to wait before retrying.121 122    For example::123 124        def http_error(exception: BaseException) -> float:125            if (126                isinstance(exception, requests.HTTPError)127                and exception.response.status_code == requests.codes.too_many_requests128            ):129                return float(exception.response.headers.get("Retry-After", "1"))130            return 60.0131 132 133        @retry(134            stop=stop_after_attempt(3),135            wait=wait_exception(http_error),136        )137        def http_get_request(url: str) -> None:138            response = requests.get(url)139            response.raise_for_status()140    """141 142    def __init__(self, predicate: typing.Callable[[BaseException], float]) -> None:143        self.predicate = predicate144 145    def __call__(self, retry_state: "RetryCallState") -> float:146        if retry_state.outcome is None:147            raise RuntimeError("__call__() called before outcome was set")148 149        exception = retry_state.outcome.exception()150        if exception is None:151            raise RuntimeError("outcome failed but the exception is None")152        return self.predicate(exception)153 154 155class wait_incrementing(wait_base):156    """Wait an incremental amount of time after each attempt.157 158    Starting at a starting value and incrementing by a value for each attempt159    (and restricting the upper limit to some maximum value).160    """161 162    def __init__(163        self,164        start: _utils.time_unit_type = 0,165        increment: _utils.time_unit_type = 100,166        max: _utils.time_unit_type = _utils.MAX_WAIT,  # noqa167    ) -> None:168        self.start = _utils.to_seconds(start)169        self.increment = _utils.to_seconds(increment)170        self.max = _utils.to_seconds(max)171 172    def __call__(self, retry_state: "RetryCallState") -> float:173        result = self.start + (self.increment * (retry_state.attempt_number - 1))174        return max(0, min(result, self.max))175 176 177class wait_exponential(wait_base):178    """Wait strategy that applies exponential backoff.179 180    It allows for a customized multiplier and an ability to restrict the181    upper and lower limits to some maximum and minimum value.182 183    The intervals are fixed (i.e. there is no jitter), so this strategy is184    suitable for balancing retries against latency when a required resource is185    unavailable for an unknown duration, but *not* suitable for resolving186    contention between multiple processes for a shared resource. Use187    wait_random_exponential for the latter case.188    """189 190    def __init__(191        self,192        multiplier: typing.Union[int, float] = 1,193        max: _utils.time_unit_type = _utils.MAX_WAIT,  # noqa194        exp_base: typing.Union[int, float] = 2,195        min: _utils.time_unit_type = 0,  # noqa196    ) -> None:197        self.multiplier = multiplier198        self.min = _utils.to_seconds(min)199        self.max = _utils.to_seconds(max)200        self.exp_base = exp_base201 202    def __call__(self, retry_state: "RetryCallState") -> float:203        try:204            exp = self.exp_base ** (retry_state.attempt_number - 1)205            result = self.multiplier * exp206        except OverflowError:207            return self.max208        return max(max(0, self.min), min(result, self.max))209 210 211class wait_random_exponential(wait_exponential):212    """Random wait with exponentially widening window.213 214    An exponential backoff strategy used to mediate contention between multiple215    uncoordinated processes for a shared resource in distributed systems. This216    is the sense in which "exponential backoff" is meant in e.g. Ethernet217    networking, and corresponds to the "Full Jitter" algorithm described in218    this blog post:219 220    https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/221 222    Each retry occurs at a random time in a geometrically expanding interval.223    It allows for a custom multiplier and an ability to restrict the upper224    limit of the random interval to some maximum value.225 226    Example::227 228        wait_random_exponential(multiplier=0.5,  # initial window 0.5s229                                max=60)          # max 60s timeout230 231    When waiting for an unavailable resource to become available again, as232    opposed to trying to resolve contention for a shared resource, the233    wait_exponential strategy (which uses a fixed interval) may be preferable.234 235    """236 237    def __call__(self, retry_state: "RetryCallState") -> float:238        high = super().__call__(retry_state=retry_state)239        return random.uniform(self.min, high)240 241 242class wait_exponential_jitter(wait_base):243    """Wait strategy that applies exponential backoff and jitter.244 245    It allows for a customized initial wait, maximum wait and jitter.246 247    This implements the strategy described here:248    https://cloud.google.com/storage/docs/retry-strategy249 250    The wait time is min(initial * 2**n + random.uniform(0, jitter), maximum)251    where n is the retry count.252    """253 254    def __init__(255        self,256        initial: float = 1,257        max: float = _utils.MAX_WAIT,  # noqa258        exp_base: float = 2,259        jitter: float = 1,260    ) -> None:261        self.initial = initial262        self.max = max263        self.exp_base = exp_base264        self.jitter = jitter265 266    def __call__(self, retry_state: "RetryCallState") -> float:267        jitter = random.uniform(0, self.jitter)268        try:269            exp = self.exp_base ** (retry_state.attempt_number - 1)270            result = self.initial * exp + jitter271        except OverflowError:272            result = self.max273        return max(0, min(result, self.max))274 
codekingpro/portable-devtools · Team Ai