Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
timeout.py285 linesDownload Raw Back to api_core
1# Copyright 2017 Google LLC2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#     http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15"""Decorators for applying timeout arguments to functions.16 17These decorators are used to wrap API methods to apply either a18Deadline-dependent (recommended), constant (DEPRECATED) or exponential19(DEPRECATED) timeout argument.20 21For example, imagine an API method that can take a while to return results,22such as one that might block until a resource is ready:23 24.. code-block:: python25 26    def is_thing_ready(timeout=None):27        response = requests.get('https://example.com/is_thing_ready')28        response.raise_for_status()29        return response.json()30 31This module allows a function like this to be wrapped so that timeouts are32automatically determined, for example:33 34.. code-block:: python35 36    timeout_ = timeout.ExponentialTimeout()37    is_thing_ready_with_timeout = timeout_(is_thing_ready)38 39    for n in range(10):40        try:41            is_thing_ready_with_timeout({'example': 'data'})42        except:43            pass44 45In this example the first call to ``is_thing_ready`` will have a relatively46small timeout (like 1 second). If the resource is available and the request47completes quickly, the loop exits. But, if the resource isn't yet available48and the request times out, it'll be retried - this time with a larger timeout.49 50In the broader context these decorators are typically combined with51:mod:`google.api_core.retry` to implement API methods with a signature that52matches ``api_method(request, timeout=None, retry=None)``.53"""54 55from __future__ import unicode_literals56 57import datetime58import functools59 60from google.api_core import datetime_helpers61 62_DEFAULT_INITIAL_TIMEOUT = 5.0  # seconds63_DEFAULT_MAXIMUM_TIMEOUT = 30.0  # seconds64_DEFAULT_TIMEOUT_MULTIPLIER = 2.065# If specified, must be in seconds. If none, deadline is not used in the66# timeout calculation.67_DEFAULT_DEADLINE = None68 69 70class TimeToDeadlineTimeout(object):71    """A decorator that decreases timeout set for an RPC based on how much time72    has left till its deadline. The deadline is calculated as73    ``now + initial_timeout`` when this decorator is first called for an rpc.74 75    In other words this decorator implements deadline semantics in terms of a76    sequence of decreasing timeouts t0 > t1 > t2 ... tn >= 0.77 78    Args:79        timeout (Optional[float]): the timeout (in seconds) to applied to the80            wrapped function. If `None`, the target function is expected to81            never timeout.82    """83 84    def __init__(self, timeout=None, clock=datetime_helpers.utcnow):85        self._timeout = timeout86        self._clock = clock87 88    def __call__(self, func):89        """Apply the timeout decorator.90 91        Args:92            func (Callable): The function to apply the timeout argument to.93                This function must accept a timeout keyword argument.94 95        Returns:96            Callable: The wrapped function.97        """98 99        first_attempt_timestamp = self._clock().timestamp()100 101        @functools.wraps(func)102        def func_with_timeout(*args, **kwargs):103            """Wrapped function that adds timeout."""104 105            remaining_timeout = self._timeout106            if remaining_timeout is not None:107                # All calculations are in seconds108                now_timestamp = self._clock().timestamp()109 110                # To avoid usage of nonlocal but still have round timeout111                # numbers for first attempt (in most cases the only attempt made112                # for an RPC.113                if now_timestamp - first_attempt_timestamp < 0.001:114                    now_timestamp = first_attempt_timestamp115 116                time_since_first_attempt = now_timestamp - first_attempt_timestamp117                # Avoid setting negative timeout118                kwargs["timeout"] = max(0, self._timeout - time_since_first_attempt)119 120            return func(*args, **kwargs)121 122        return func_with_timeout123 124    def __str__(self):125        return "<TimeToDeadlineTimeout timeout={:.1f}>".format(self._timeout)126 127 128class ConstantTimeout(object):129    """A decorator that adds a constant timeout argument.130 131    DEPRECATED: use ``TimeToDeadlineTimeout`` instead.132 133    This is effectively equivalent to134    ``functools.partial(func, timeout=timeout)``.135 136    Args:137        timeout (Optional[float]): the timeout (in seconds) to applied to the138            wrapped function. If `None`, the target function is expected to139            never timeout.140    """141 142    def __init__(self, timeout=None):143        self._timeout = timeout144 145    def __call__(self, func):146        """Apply the timeout decorator.147 148        Args:149            func (Callable): The function to apply the timeout argument to.150                This function must accept a timeout keyword argument.151 152        Returns:153            Callable: The wrapped function.154        """155 156        @functools.wraps(func)157        def func_with_timeout(*args, **kwargs):158            """Wrapped function that adds timeout."""159            kwargs["timeout"] = self._timeout160            return func(*args, **kwargs)161 162        return func_with_timeout163 164    def __str__(self):165        return "<ConstantTimeout timeout={:.1f}>".format(self._timeout)166 167 168def _exponential_timeout_generator(initial, maximum, multiplier, deadline):169    """A generator that yields exponential timeout values.170 171    Args:172        initial (float): The initial timeout.173        maximum (float): The maximum timeout.174        multiplier (float): The multiplier applied to the timeout.175        deadline (float): The overall deadline across all invocations.176 177    Yields:178        float: A timeout value.179    """180    if deadline is not None:181        deadline_datetime = datetime_helpers.utcnow() + datetime.timedelta(182            seconds=deadline183        )184    else:185        deadline_datetime = datetime.datetime.max186 187    timeout = initial188    while True:189        now = datetime_helpers.utcnow()190        yield min(191            # The calculated timeout based on invocations.192            timeout,193            # The set maximum timeout.194            maximum,195            # The remaining time before the deadline is reached.196            float((deadline_datetime - now).seconds),197        )198        timeout = timeout * multiplier199 200 201class ExponentialTimeout(object):202    """A decorator that adds an exponentially increasing timeout argument.203 204    DEPRECATED: the concept of incrementing timeout exponentially has been205    deprecated. Use ``TimeToDeadlineTimeout`` instead.206 207    This is useful if a function is called multiple times. Each time the208    function is called this decorator will calculate a new timeout parameter209    based on the the number of times the function has been called.210 211    For example212 213    .. code-block:: python214 215    Args:216        initial (float): The initial timeout to pass.217        maximum (float): The maximum timeout for any one call.218        multiplier (float): The multiplier applied to the timeout for each219            invocation.220        deadline (Optional[float]): The overall deadline across all221            invocations. This is used to prevent a very large calculated222            timeout from pushing the overall execution time over the deadline.223            This is especially useful in conjunction with224            :mod:`google.api_core.retry`. If ``None``, the timeouts will not225            be adjusted to accommodate an overall deadline.226    """227 228    def __init__(229        self,230        initial=_DEFAULT_INITIAL_TIMEOUT,231        maximum=_DEFAULT_MAXIMUM_TIMEOUT,232        multiplier=_DEFAULT_TIMEOUT_MULTIPLIER,233        deadline=_DEFAULT_DEADLINE,234    ):235        self._initial = initial236        self._maximum = maximum237        self._multiplier = multiplier238        self._deadline = deadline239 240    def with_deadline(self, deadline):241        """Return a copy of this timeout with the given deadline.242 243        Args:244            deadline (float): The overall deadline across all invocations.245 246        Returns:247            ExponentialTimeout: A new instance with the given deadline.248        """249        return ExponentialTimeout(250            initial=self._initial,251            maximum=self._maximum,252            multiplier=self._multiplier,253            deadline=deadline,254        )255 256    def __call__(self, func):257        """Apply the timeout decorator.258 259        Args:260            func (Callable): The function to apply the timeout argument to.261                This function must accept a timeout keyword argument.262 263        Returns:264            Callable: The wrapped function.265        """266        timeouts = _exponential_timeout_generator(267            self._initial, self._maximum, self._multiplier, self._deadline268        )269 270        @functools.wraps(func)271        def func_with_timeout(*args, **kwargs):272            """Wrapped function that adds timeout."""273            kwargs["timeout"] = next(timeouts)274            return func(*args, **kwargs)275 276        return func_with_timeout277 278    def __str__(self):279        return (280            "<ExponentialTimeout initial={:.1f}, maximum={:.1f}, "281            "multiplier={:.1f}, deadline={:.1f}>".format(282                self._initial, self._maximum, self._multiplier, self._deadline283            )284        )285 
codekingpro/portable-devtools · Team Ai