Retries an HTTP request multiple times while handling errors. If after all retries the request still fails, last error is either returned as return value (for HTTP 5xx errors) or thrown (for ssl.SSLError). Args: http: Http object to be used to execute request. num_retries:
(
http, num_retries, req_type, sleep, rand, uri, method, *args, **kwargs
)
| 148 | |
| 149 | |
| 150 | def _retry_request( |
| 151 | http, num_retries, req_type, sleep, rand, uri, method, *args, **kwargs |
| 152 | ): |
| 153 | """Retries an HTTP request multiple times while handling errors. |
| 154 | |
| 155 | If after all retries the request still fails, last error is either returned as |
| 156 | return value (for HTTP 5xx errors) or thrown (for ssl.SSLError). |
| 157 | |
| 158 | Args: |
| 159 | http: Http object to be used to execute request. |
| 160 | num_retries: Maximum number of retries. |
| 161 | req_type: Type of the request (used for logging retries). |
| 162 | sleep, rand: Functions to sleep for random time between retries. |
| 163 | uri: URI to be requested. |
| 164 | method: HTTP method to be used. |
| 165 | args, kwargs: Additional arguments passed to http.request. |
| 166 | |
| 167 | Returns: |
| 168 | resp, content - Response from the http request (may be HTTP 5xx). |
| 169 | """ |
| 170 | resp = None |
| 171 | content = None |
| 172 | exception = None |
| 173 | for retry_num in range(num_retries + 1): |
| 174 | if retry_num > 0: |
| 175 | # Sleep before retrying. |
| 176 | sleep_time = rand() * 2**retry_num |
| 177 | LOGGER.warning( |
| 178 | "Sleeping %.2f seconds before retry %d of %d for %s: %s %s, after %s", |
| 179 | sleep_time, |
| 180 | retry_num, |
| 181 | num_retries, |
| 182 | req_type, |
| 183 | method, |
| 184 | uri, |
| 185 | resp.status if resp else exception, |
| 186 | ) |
| 187 | sleep(sleep_time) |
| 188 | |
| 189 | try: |
| 190 | exception = None |
| 191 | resp, content = http.request(uri, method, *args, **kwargs) |
| 192 | # Retry on SSL errors and socket timeout errors. |
| 193 | except _ssl_SSLError as ssl_error: |
| 194 | exception = ssl_error |
| 195 | except socket.timeout as socket_timeout: |
| 196 | # Needs to be before socket.error as it's a subclass of OSError |
| 197 | # socket.timeout has no errorcode |
| 198 | exception = socket_timeout |
| 199 | except ConnectionError as connection_error: |
| 200 | # Needs to be before socket.error as it's a subclass of OSError |
| 201 | exception = connection_error |
| 202 | except OSError as socket_error: |
| 203 | # errno's contents differ by platform, so we have to match by name. |
| 204 | # Some of these same errors may have been caught above, e.g. ECONNRESET *should* be |
| 205 | # raised as a ConnectionError, but some libraries will raise it as a socket.error |
| 206 | # with an errno corresponding to ECONNRESET |
| 207 | if socket.errno.errorcode.get(socket_error.errno) not in { |
no test coverage detected
searching dependent graphs…