Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import collections | 5 import collections |
| 6 import copy | 6 import copy |
| 7 import json | 7 import json |
| 8 import logging | 8 import logging |
| 9 import os | 9 import os |
| 10 import re | 10 import re |
| 11 import socket | 11 import socket |
| 12 import sys | 12 import sys |
| 13 import time | 13 import time |
| 14 | 14 |
| 15 import httplib2 | 15 import httplib2 |
| 16 import oauth2client.client | 16 import oauth2client.client |
| 17 | 17 |
| 18 from googleapiclient import errors | |
| 18 from infra_libs.ts_mon.common import http_metrics | 19 from infra_libs.ts_mon.common import http_metrics |
| 19 | 20 |
| 20 DEFAULT_SCOPES = ['email'] | 21 DEFAULT_SCOPES = ['email'] |
| 21 | 22 |
| 22 # default timeout for http requests, in seconds | 23 # default timeout for http requests, in seconds |
| 23 DEFAULT_TIMEOUT = 30 | 24 DEFAULT_TIMEOUT = 30 |
| 24 | 25 |
| 25 # This is part of the API. | 26 # This is part of the API. |
| 26 if sys.platform.startswith('win'): # pragma: no cover | 27 if sys.platform.startswith('win'): # pragma: no cover |
| 27 SERVICE_ACCOUNTS_CREDS_ROOT = 'C:\\creds\\service_accounts' | 28 SERVICE_ACCOUNTS_CREDS_ROOT = 'C:\\creds\\service_accounts' |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 credentials_filename, | 155 credentials_filename, |
| 155 scope=scope, | 156 scope=scope, |
| 156 service_accounts_creds_root=service_accounts_creds_root) | 157 service_accounts_creds_root=service_accounts_creds_root) |
| 157 | 158 |
| 158 if http_identifier: | 159 if http_identifier: |
| 159 http = InstrumentedHttp(http_identifier, timeout=timeout) | 160 http = InstrumentedHttp(http_identifier, timeout=timeout) |
| 160 else: | 161 else: |
| 161 http = httplib2.Http(timeout=timeout) | 162 http = httplib2.Http(timeout=timeout) |
| 162 return creds.authorize(http) | 163 return creds.authorize(http) |
| 163 | 164 |
| 165 class RetryableHttp(object): | |
|
Sergey Berezin
2016/07/06 20:13:28
nit (spelling): Retriable
Sergey Berezin
2016/07/06 20:13:29
Inherit from httplib2.Http, and call base class's
tnn
2016/07/06 22:05:18
Done.
| |
| 166 """A httplib2.Http object that retries on failure.""" | |
| 167 | |
| 168 def __init__(self, http_obj, max_tries=5, | |
| 169 retrying_statuses=range(500,599)): | |
|
Sergey Berezin
2016/07/06 20:13:28
For efficiency, I'd either make it a set(range(500
tnn
2016/07/06 22:05:17
Done.
| |
| 170 """ | |
| 171 Args: | |
| 172 http_obj: an httplib2.Http instance | |
| 173 max_tries: a number of maximum tries | |
| 174 retrying_status_codes: a set of HTTP status codes that cause a retry | |
| 175 """ | |
| 176 self.http_obj = http_obj | |
| 177 self.max_tries = max_tries | |
| 178 self.retrying_statuses = retrying_statuses | |
| 179 | |
| 180 def request(self, uri, method="GET", body=None, *args, **kwargs): | |
|
Sergey Berezin
2016/07/06 20:13:28
nit: use single quotes for strings if possible: 'G
tnn
2016/07/06 22:05:18
Done.
| |
| 181 for i in range(1, self.max_tries + 1): | |
| 182 try: | |
| 183 response, content = self.http_obj.request( | |
| 184 uri, method, body, *args, **kwargs) | |
|
Sergey Berezin
2016/07/06 20:13:29
nit: indent 4 spaces relative to the prev. line.
tnn
2016/07/06 22:05:18
I swear it looked like 4 spaces in my vim :S It tu
| |
| 185 | |
| 186 if response.status in self.retrying_statuses: | |
| 187 logging.info("RetryableHttp retries (%d) on receiving status: %d", | |
|
Sergey Berezin
2016/07/06 20:13:28
nit (wording suggestion):
logging.info(
'R
tnn
2016/07/06 22:05:17
Done.
| |
| 188 i, response.status) | |
| 189 continue | |
| 190 except (ValueError, errors.Error, | |
| 191 socket.timeout, socket.error, socket.herror, socket.gaierror, | |
|
Sergey Berezin
2016/07/06 20:13:28
nit: we always indent arguments to align:
your_
tnn
2016/07/06 22:05:18
Done.
| |
| 192 httplib2.HttpLib2Error) as error: | |
| 193 if i == self.max_tries: | |
| 194 logging.warning("RetryableHttp fails on exception: %s", error) | |
|
Sergey Berezin
2016/07/06 20:13:29
nit: 'single quotes'
tnn
2016/07/06 22:05:18
Done.
| |
| 195 raise | |
| 196 else: | |
| 197 logging.info("RetryableHttp retries (%d) on exception: %s", i, error) | |
|
Sergey Berezin
2016/07/06 20:13:28
nit: 'single quotes', and similar wording suggesti
tnn
2016/07/06 22:05:18
Done.
| |
| 198 continue | |
| 199 break | |
| 200 | |
| 201 return response, content | |
| 202 | |
| 164 | 203 |
| 165 class InstrumentedHttp(httplib2.Http): | 204 class InstrumentedHttp(httplib2.Http): |
| 166 """A httplib2.Http object that reports ts_mon metrics about its requests.""" | 205 """A httplib2.Http object that reports ts_mon metrics about its requests.""" |
| 167 | 206 |
| 168 def __init__(self, name, time_fn=time.time, timeout=DEFAULT_TIMEOUT, | 207 def __init__(self, name, time_fn=time.time, timeout=DEFAULT_TIMEOUT, |
| 169 **kwargs): | 208 **kwargs): |
| 170 """ | 209 """ |
| 171 Args: | 210 Args: |
| 172 name: An identifier for the HTTP requests made by this object. | 211 name: An identifier for the HTTP requests made by this object. |
| 173 time_fn: Function returning the current time in seconds. Use for testing | 212 time_fn: Function returning the current time in seconds. Use for testing |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 self.requests_made.append(self.HttpCall(uri, method, body, headers)) | 296 self.requests_made.append(self.HttpCall(uri, method, body, headers)) |
| 258 headers = None | 297 headers = None |
| 259 body = None | 298 body = None |
| 260 for candidate in self._uris: | 299 for candidate in self._uris: |
| 261 if candidate[0].match(uri): | 300 if candidate[0].match(uri): |
| 262 _, headers, body = candidate | 301 _, headers, body = candidate |
| 263 break | 302 break |
| 264 if not headers: | 303 if not headers: |
| 265 raise AssertionError("Unexpected request to %s" % uri) | 304 raise AssertionError("Unexpected request to %s" % uri) |
| 266 return httplib2.Response(headers), body | 305 return httplib2.Response(headers), body |
| OLD | NEW |