|
13 | 13 | # limitations under the License.
|
14 | 14 |
|
15 | 15 | import socket
|
16 |
| -import time |
17 | 16 | from functools import wraps
|
18 | 17 | from typing import Any, Callable, Dict, Optional
|
19 | 18 | from urllib.parse import urljoin
|
20 | 19 |
|
21 |
| -import lightning_cloud |
22 | 20 | import requests
|
23 |
| -import urllib3 |
24 |
| -from lightning_cloud.rest_client import create_swagger_client, GridRestClient |
| 21 | + |
| 22 | +# for backwards compatibility |
| 23 | +from lightning_cloud.rest_client import create_swagger_client, GridRestClient, LightningClient # noqa: F401 |
25 | 24 | from requests import Session
|
26 | 25 | from requests.adapters import HTTPAdapter
|
27 | 26 | from requests.exceptions import ConnectionError, ConnectTimeout, ReadTimeout
|
@@ -87,7 +86,6 @@ def _find_free_network_port_cloudspace():
|
87 | 86 |
|
88 | 87 | _CONNECTION_RETRY_TOTAL = 2880
|
89 | 88 | _CONNECTION_RETRY_BACKOFF_FACTOR = 0.5
|
90 |
| -_DEFAULT_BACKOFF_MAX = 5 * 60 # seconds |
91 | 89 | _DEFAULT_REQUEST_TIMEOUT = 30 # seconds
|
92 | 90 |
|
93 | 91 |
|
@@ -119,75 +117,6 @@ def _check_service_url_is_ready(url: str, timeout: float = 5, metadata="") -> bo
|
119 | 117 | return False
|
120 | 118 |
|
121 | 119 |
|
122 |
| -def _get_next_backoff_time(num_retries: int, backoff_value: float = 0.5) -> float: |
123 |
| - next_backoff_value = backoff_value * (2 ** (num_retries - 1)) |
124 |
| - return min(_DEFAULT_BACKOFF_MAX, next_backoff_value) |
125 |
| - |
126 |
| - |
127 |
| -def _retry_wrapper(self, func: Callable, max_tries: Optional[int] = None) -> Callable: |
128 |
| - """Returns the function decorated by a wrapper that retries the call several times if a connection error occurs. |
129 |
| -
|
130 |
| - The retries follow an exponential backoff. |
131 |
| -
|
132 |
| - """ |
133 |
| - |
134 |
| - @wraps(func) |
135 |
| - def wrapped(*args: Any, **kwargs: Any) -> Any: |
136 |
| - consecutive_errors = 0 |
137 |
| - |
138 |
| - while True: |
139 |
| - try: |
140 |
| - return func(self, *args, **kwargs) |
141 |
| - except (lightning_cloud.openapi.rest.ApiException, urllib3.exceptions.HTTPError) as ex: |
142 |
| - # retry if the backend fails with all errors except 4xx but not 408 - (Request Timeout) |
143 |
| - if ( |
144 |
| - isinstance(ex, urllib3.exceptions.HTTPError) |
145 |
| - or ex.status in (408, 409) |
146 |
| - or not str(ex.status).startswith("4") |
147 |
| - ): |
148 |
| - consecutive_errors += 1 |
149 |
| - backoff_time = _get_next_backoff_time(consecutive_errors) |
150 |
| - |
151 |
| - msg = ( |
152 |
| - f"error: {str(ex)}" |
153 |
| - if isinstance(ex, urllib3.exceptions.HTTPError) |
154 |
| - else f"response: {ex.status}" |
155 |
| - ) |
156 |
| - logger.debug( |
157 |
| - f"The {func.__name__} request failed to reach the server, {msg}." |
158 |
| - f" Retrying after {backoff_time} seconds." |
159 |
| - ) |
160 |
| - |
161 |
| - if max_tries is not None and consecutive_errors == max_tries: |
162 |
| - raise Exception(f"The {func.__name__} request failed to reach the server, {msg}.") |
163 |
| - |
164 |
| - time.sleep(backoff_time) |
165 |
| - else: |
166 |
| - raise ex |
167 |
| - |
168 |
| - return wrapped |
169 |
| - |
170 |
| - |
171 |
| -class LightningClient(GridRestClient): |
172 |
| - """The LightningClient is a wrapper around the GridRestClient. |
173 |
| -
|
174 |
| - It wraps all methods to monitor connection exceptions and employs a retry strategy. |
175 |
| -
|
176 |
| - Args: |
177 |
| - retry: Whether API calls should follow a retry mechanism with exponential backoff. |
178 |
| - max_tries: Maximum number of attempts (or -1 to retry forever). |
179 |
| -
|
180 |
| - """ |
181 |
| - |
182 |
| - def __init__(self, retry: bool = True, max_tries: Optional[int] = None) -> None: |
183 |
| - super().__init__(api_client=create_swagger_client()) |
184 |
| - if retry: |
185 |
| - for base_class in GridRestClient.__mro__: |
186 |
| - for name, attribute in base_class.__dict__.items(): |
187 |
| - if callable(attribute) and attribute.__name__ != "__init__": |
188 |
| - setattr(self, name, _retry_wrapper(self, attribute, max_tries=max_tries)) |
189 |
| - |
190 |
| - |
191 | 120 | class CustomRetryAdapter(HTTPAdapter):
|
192 | 121 | def __init__(self, *args: Any, **kwargs: Any):
|
193 | 122 | self.timeout = kwargs.pop("timeout", _DEFAULT_REQUEST_TIMEOUT)
|
|
0 commit comments