utils: do not log requests errors when the resource is down (#72914)
gitea/passerelle/pipeline/head This commit looks good Details

This commit is contained in:
Benjamin Dauvergne 2023-03-15 20:14:23 +01:00
parent d42985797b
commit f914b8542a
2 changed files with 89 additions and 4 deletions

View File

@ -254,6 +254,15 @@ def log_http_request(
# - use a proxy for HTTP and HTTPS if resource.http_proxy exists
def to_registry_key(value):
if isinstance(value, dict):
return tuple((key, to_registry_key(value[key])) for key in sorted(value.keys()))
elif isinstance(value, list):
return tuple(to_registry_key(x) for x in value)
else:
return value
class Request(RequestSession):
ADAPTER_REGISTRY = {} # connection pooling
log_requests_errors = True
@ -262,7 +271,10 @@ class Request(RequestSession):
self.logger = kwargs.pop('logger')
self.resource = kwargs.pop('resource', None)
resource_log_requests_errors = getattr(self.resource, 'log_requests_errors', True)
self.log_requests_errors = kwargs.pop('log_requests_errors', resource_log_requests_errors)
resource_is_down = self.resource.down() if hasattr(self.resource, 'down') else False
self.log_requests_errors = kwargs.pop(
'log_requests_errors', resource_log_requests_errors and not resource_is_down
)
timeout = kwargs.pop('timeout', None)
super().__init__(*args, **kwargs)
if self.resource:
@ -271,11 +283,12 @@ class Request(RequestSession):
requests_max_retries = dict(settings.REQUESTS_MAX_RETRIES)
if getattr(self.resource, 'requests_max_retries', None):
requests_max_retries = dict(self.resource.requests_max_retries)
if requests_max_retries:
if requests_max_retries and not resource_is_down:
requests_max_retries.setdefault('read', None)
http_adapter_init_kwargs['max_retries'] = Retry(**requests_max_retries)
adapter = Request.ADAPTER_REGISTRY.setdefault(
type(self.resource), HTTPAdapter(**http_adapter_init_kwargs)
(type(self.resource), to_registry_key(http_adapter_init_kwargs)),
HTTPAdapter(**http_adapter_init_kwargs),
)
self.mount('https://', adapter)
self.mount('http://', adapter)

View File

@ -7,7 +7,8 @@ import requests
import responses
from django.test import override_settings
from httmock import HTTMock, response, urlmatch
from urllib3.exceptions import ReadTimeoutError
from responses.registries import OrderedRegistry
from urllib3.exceptions import ConnectionError, ReadTimeoutError
from passerelle.utils import CaseInsensitiveDict, Request, log_http_request
from passerelle.utils.http_authenticators import HawkAuth
@ -665,3 +666,74 @@ def test_requests_substitution(settings):
requests.get('https://example.com/html?bar=foo', params={'foo': 'bar'}).text
== '<html>\n<a href="http://example.internal/path/">\n<a/></html>'
)
@responses.activate(registry=OrderedRegistry) # pylint: disable=unexpected-keyword-arg,no-value-for-parameter
def test_requests_resource_down():
from passerelle.base.models import BaseResource
resource = mock.Mock()
resource.requests_max_retries = {}
resource.slug = 'test'
resource.get_connector_slug.return_value = 'cmis'
resource.get_settings = lambda: BaseResource.get_settings(resource)
resource.get_setting = lambda name: BaseResource.get_setting(resource, name)
resource.down = mock.Mock(return_value=False)
logger = mock.Mock()
requests = Request(resource=resource, logger=logger)
responses.add(
responses.GET,
"https://example.com/exception",
body=ConnectionError('down'),
)
with pytest.raises(ConnectionError):
requests.get('https://example.com/exception')
assert logger.error.call_count == 1
assert logger.info.call_count == 0
responses.add(
responses.GET,
"https://example.com/exception",
body=ConnectionError('down'),
)
logger = mock.Mock()
resource.down.return_value = True
requests = Request(resource=resource, logger=logger)
with pytest.raises(ConnectionError):
requests.get('https://example.com/exception')
assert logger.error.call_count == 0
assert logger.info.call_count == 1
responses.add(
responses.GET,
"https://example.com/exception",
body='Error',
status=500,
)
responses.add(
responses.GET,
"https://example.com/exception",
body='ok',
)
resource.down.return_value = False
resource.requests_max_retries = {
'total': 3,
'backoff_factor': 0.001,
'status_forcelist': [500],
'connect': 1,
'read': 1,
}
requests = Request(resource=resource, logger=logger)
assert requests.get('https://example.com/exception').text == 'ok'
responses.add(
responses.GET,
"https://example.com/exception",
body='Error',
status=500,
)
resource.down.return_value = True
requests = Request(resource=resource, logger=logger)
assert requests.get('https://example.com/exception').status_code == 500