diff options
Diffstat (limited to 'google/api_core/gapic_v1/config.py')
-rw-r--r-- | google/api_core/gapic_v1/config.py | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/google/api_core/gapic_v1/config.py b/google/api_core/gapic_v1/config.py new file mode 100644 index 0000000..9c72287 --- /dev/null +++ b/google/api_core/gapic_v1/config.py @@ -0,0 +1,166 @@ +# Copyright 2017 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Helpers for loading gapic configuration data. + +The Google API generator creates supplementary configuration for each RPC +method to tell the client library how to deal with retries and timeouts. +""" + +import collections + +import grpc + +from google.api_core import exceptions +from google.api_core import retry +from google.api_core import timeout + + +_MILLIS_PER_SECOND = 1000.0 + + +def _exception_class_for_grpc_status_name(name): + """Returns the Google API exception class for a gRPC error code name. + + Args: + name (str): The name of the gRPC status code, for example, + ``UNAVAILABLE``. + + Returns: + :func:`type`: The appropriate subclass of + :class:`google.api_core.exceptions.GoogleAPICallError`. + """ + return exceptions.exception_class_for_grpc_status(getattr(grpc.StatusCode, name)) + + +def _retry_from_retry_config(retry_params, retry_codes, retry_impl=retry.Retry): + """Creates a Retry object given a gapic retry configuration. + + Args: + retry_params (dict): The retry parameter values, for example:: + + { + "initial_retry_delay_millis": 1000, + "retry_delay_multiplier": 2.5, + "max_retry_delay_millis": 120000, + "initial_rpc_timeout_millis": 120000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 120000, + "total_timeout_millis": 600000 + } + + retry_codes (sequence[str]): The list of retryable gRPC error code + names. + + Returns: + google.api_core.retry.Retry: The default retry object for the method. + """ + exception_classes = [ + _exception_class_for_grpc_status_name(code) for code in retry_codes + ] + return retry_impl( + retry.if_exception_type(*exception_classes), + initial=(retry_params["initial_retry_delay_millis"] / _MILLIS_PER_SECOND), + maximum=(retry_params["max_retry_delay_millis"] / _MILLIS_PER_SECOND), + multiplier=retry_params["retry_delay_multiplier"], + deadline=retry_params["total_timeout_millis"] / _MILLIS_PER_SECOND, + ) + + +def _timeout_from_retry_config(retry_params): + """Creates a ExponentialTimeout object given a gapic retry configuration. + + Args: + retry_params (dict): The retry parameter values, for example:: + + { + "initial_retry_delay_millis": 1000, + "retry_delay_multiplier": 2.5, + "max_retry_delay_millis": 120000, + "initial_rpc_timeout_millis": 120000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 120000, + "total_timeout_millis": 600000 + } + + Returns: + google.api_core.retry.ExponentialTimeout: The default time object for + the method. + """ + return timeout.ExponentialTimeout( + initial=(retry_params["initial_rpc_timeout_millis"] / _MILLIS_PER_SECOND), + maximum=(retry_params["max_rpc_timeout_millis"] / _MILLIS_PER_SECOND), + multiplier=retry_params["rpc_timeout_multiplier"], + deadline=(retry_params["total_timeout_millis"] / _MILLIS_PER_SECOND), + ) + + +MethodConfig = collections.namedtuple("MethodConfig", ["retry", "timeout"]) + + +def parse_method_configs(interface_config, retry_impl=retry.Retry): + """Creates default retry and timeout objects for each method in a gapic + interface config. + + Args: + interface_config (Mapping): The interface config section of the full + gapic library config. For example, If the full configuration has + an interface named ``google.example.v1.ExampleService`` you would + pass in just that interface's configuration, for example + ``gapic_config['interfaces']['google.example.v1.ExampleService']``. + retry_impl (Callable): The constructor that creates a retry decorator + that will be applied to the method based on method configs. + + Returns: + Mapping[str, MethodConfig]: A mapping of RPC method names to their + configuration. + """ + # Grab all the retry codes + retry_codes_map = { + name: retry_codes + for name, retry_codes in interface_config.get("retry_codes", {}).items() + } + + # Grab all of the retry params + retry_params_map = { + name: retry_params + for name, retry_params in interface_config.get("retry_params", {}).items() + } + + # Iterate through all the API methods and create a flat MethodConfig + # instance for each one. + method_configs = {} + + for method_name, method_params in interface_config.get("methods", {}).items(): + retry_params_name = method_params.get("retry_params_name") + + if retry_params_name is not None: + retry_params = retry_params_map[retry_params_name] + retry_ = _retry_from_retry_config( + retry_params, + retry_codes_map[method_params["retry_codes_name"]], + retry_impl, + ) + timeout_ = _timeout_from_retry_config(retry_params) + + # No retry config, so this is a non-retryable method. + else: + retry_ = None + timeout_ = timeout.ConstantTimeout( + method_params["timeout_millis"] / _MILLIS_PER_SECOND + ) + + method_configs[method_name] = MethodConfig(retry=retry_, timeout=timeout_) + + return method_configs |