Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add connection timeouts to botocore #325

Merged
merged 2 commits into from
Jul 21, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions botocore/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@


logger = logging.getLogger(__name__)

DEFAULT_TIMEOUT = 60

class Endpoint(object):
"""
Expand All @@ -44,7 +44,7 @@ class Endpoint(object):
"""

def __init__(self, service, region_name, host, auth, proxies=None,
verify=True):
verify=True, timeout=DEFAULT_TIMEOUT):
self.service = service
self.session = self.service.session
self.region_name = region_name
Expand All @@ -55,6 +55,7 @@ def __init__(self, service, region_name, host, auth, proxies=None,
proxies = {}
self.proxies = proxies
self.http_session = Session()
self.timeout = timeout
self._lock = threading.Lock()

def __repr__(self):
Expand Down Expand Up @@ -127,7 +128,7 @@ def _get_response(self, request, operation, attempts):
http_response = self.http_session.send(
request, verify=self.verify,
stream=operation.is_streaming(),
proxies=self.proxies)
proxies=self.proxies, timeout=self.timeout)
except Exception as e:
logger.debug("Exception received when sending HTTP request.",
exc_info=True)
Expand Down
4 changes: 2 additions & 2 deletions botocore/retryhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import logging
from binascii import crc32

from botocore.vendored.requests import ConnectionError
from botocore.vendored.requests import ConnectionError, Timeout
from botocore.vendored.requests.packages.urllib3.exceptions import ClosedPoolError

from botocore.exceptions import ChecksumError
Expand All @@ -29,7 +29,7 @@
# to get more specific exceptions from requests we can update
# this mapping with more specific exceptions.
EXCEPTION_MAP = {
'GENERAL_CONNECTION_ERROR': [ConnectionError, ClosedPoolError],
'GENERAL_CONNECTION_ERROR': [ConnectionError, ClosedPoolError, Timeout],
}


Expand Down
21 changes: 14 additions & 7 deletions tests/unit/test_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import six

from botocore.endpoint import get_endpoint, QueryEndpoint, JSONEndpoint, \
RestEndpoint
RestEndpoint, DEFAULT_TIMEOUT
from botocore.auth import SigV4Auth
from botocore.session import Session
from botocore.exceptions import UnknownServiceStyle
Expand Down Expand Up @@ -173,18 +173,25 @@ def test_make_request(self):
prepared_request = self.http_session.send.call_args[0][0]
self.http_session.send.assert_called_with(
prepared_request, verify=True, stream=False,
proxies={})
proxies={}, timeout=DEFAULT_TIMEOUT)
self.get_response.assert_called_with(self.service.session,
self.op, sentinel.HTTP_RETURN_VALUE)

def test_timeout_can_be_specified(self):
timeout_override = 120
self.endpoint.timeout = timeout_override
self.endpoint.make_request(self.op, {})
kwargs = self.http_session.send.call_args[1]
self.assertEqual(kwargs['timeout'], timeout_override)

def test_make_request_with_proxies(self):
proxies = {'http': 'http://localhost:8888'}
self.endpoint.proxies = proxies
self.endpoint.make_request(self.op, {})
prepared_request = self.http_session.send.call_args[0][0]
self.http_session.send.assert_called_with(
prepared_request, verify=True, stream=False,
proxies=proxies)
proxies=proxies, timeout=DEFAULT_TIMEOUT)

def test_make_request_with_no_auth(self):
self.endpoint.auth = None
Expand All @@ -211,7 +218,7 @@ def test_make_request(self):
prepared_request = self.http_session.send.call_args[0][0]
self.http_session.send.assert_called_with(
prepared_request, verify=True, stream=False,
proxies={})
proxies={}, timeout=DEFAULT_TIMEOUT)
self.get_response.assert_called_with(self.service.session,
self.op, sentinel.HTTP_RETURN_VALUE)

Expand All @@ -226,7 +233,7 @@ def test_make_request(self):
prepared_request = self.http_session.send.call_args[0][0]
self.http_session.send.assert_called_with(
prepared_request, verify=True, stream=False,
proxies={})
proxies={}, timeout=DEFAULT_TIMEOUT)


class TestJSONEndpointAnonymousOp(TestJSONEndpoint):
Expand All @@ -242,7 +249,7 @@ def test_make_request(self):
prepared_request = self.http_session.send.call_args[0][0]
self.http_session.send.assert_called_with(
prepared_request, verify=True, stream=False,
proxies={})
proxies={}, timeout=DEFAULT_TIMEOUT)


class TestRestEndpoint(TestEndpointBase):
Expand Down Expand Up @@ -273,7 +280,7 @@ def test_make_request(self):
prepared_request = self.http_session.send.call_args[0][0]
self.http_session.send.assert_called_with(
prepared_request, verify=True, stream=False,
proxies={})
proxies={}, timeout=DEFAULT_TIMEOUT)


class TestRetryInterface(BaseSessionTest):
Expand Down
11 changes: 10 additions & 1 deletion tests/unit/test_retryhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from tests import unittest

import mock
from botocore.vendored.requests import ConnectionError
from botocore.vendored.requests import ConnectionError, Timeout
from botocore.vendored.requests.packages.urllib3.exceptions import ClosedPoolError

from botocore import retryhandler
Expand Down Expand Up @@ -213,6 +213,15 @@ def test_create_retry_handler_with_socket_errors(self):
sleep_time = handler(response=None, attempts=1,
caught_exception=ValueError())

def test_connection_timeouts_are_retried(self):
# If a connection times out, we get a Timout exception
# from requests. We should be retrying those.
handler = retryhandler.create_retry_handler(
self.retry_config, operation_name='OperationBar')
sleep_time = handler(response=None, attempts=1,
caught_exception=Timeout())
self.assertEqual(sleep_time, 1)

def test_retry_pool_closed_errors(self):
# A ClosedPoolError is retried (this is a workaround for a urllib3
# bug). Can be removed once we upgrade to requests 2.0.0.
Expand Down