-
Notifications
You must be signed in to change notification settings - Fork 196
Add connection/read timeout for requests adapter #342
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! I've left a note inline. It'd also be really useful to actually add tests for the timeout functionality that we're implicitly also adding to our lower-level classes.
hyper/contrib.py
Outdated
| proxy_host=proxy_netloc, | ||
| proxy_headers=proxy_headers) | ||
| proxy_headers=proxy_headers, | ||
| **kwargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be sending arbitrary kwargs from Requests to hyper: there's no reason to assume that those kwargs will match in any sensible way. We should aim to be explicit here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I had change to explicit timeout and add more timeout tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! I was going to work on timeouts this week but you have started earlier :)
I have one more note on this: the _create_tunnel function of http11 module should respect the timeout too.
PS: Related issue: #187
hyper/http11/connection.py
Outdated
| self.parser = Parser() | ||
|
|
||
| # timeout | ||
| timeout = kwargs.get('timeout') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
timeout should be optional. I think it should be None - that means no timeout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, timeout is optional and default None, is equivalent to socket.setblocking(1)
|
timeout is optional, the default value is None, means that it will block connection/read, it is the same as request/adapters.py: it also can set timeout to socket._GLOBAL_DEFAULT_TIMEOUT |
hyper/contrib.py
Outdated
| proxy = prepend_scheme_if_needed(proxy, 'http') | ||
|
|
||
| parsed = urlparse(request.url) | ||
| timeout = kwargs.get('timeout') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just add timeout to our list of kwargs.
test/test_integration.py
Outdated
| conn = self.get_connection() | ||
| try: | ||
| conn.connect() | ||
| assert False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be pytest.fail, and generally should go in an else block.
test/test_integration.py
Outdated
|
|
||
| # Wait for request | ||
| req_event.wait(5) | ||
| # Now, send the headers for the response. This response has no body |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is misleading.
test/test_integration.py
Outdated
| time.sleep(1) | ||
|
|
||
| # Now, send the headers for the response. This response has no body | ||
| f = build_headers_frame( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We never actually need to send this, and doing so could cause exceptions, so let's not send any data here.
test/test_integration.py
Outdated
|
|
||
| try: | ||
| conn.get_response() | ||
| assert False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same note about pytest.fail and else blocks.
|
|
||
| send_event.wait(5) | ||
|
|
||
| assert data[0].startswith(b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How can this possibly pass? If the connection fails, we're never going to see this data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default timeout None will block connect, so it will connect sucess and go on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry, I see that. Thanks!
test/test_integration.py
Outdated
|
|
||
| def socket_handler(listener): | ||
| time.sleep(1) | ||
| sock = listener.accept()[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No point calling accept: it'll usually fail, and throw exceptions, which we don't want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if connection timeout smaller than 1s, it will throw timeout exception, in this test connection timeout is set to 0.5, so it will throw exception as expect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but this exception is not caught, meaning it'll be logged and generally treated badly. We shouldn't do anything in the background thread that we know will fail, and accept will fail here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it, I just updated
| def __init__(self, host, port=None, secure=None, ssl_context=None, | ||
| proxy_host=None, proxy_port=None, proxy_headers=None, | ||
| **kwargs): | ||
| timeout=None, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably add this to the common HTTPConnection object as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok,I just added
|
|
||
| assert c._connect_timeout == 5 | ||
| assert c._read_timeout == 60 | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need these tests for HTTP/2 as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok,I add this in test/test_hyper.py
test/test_integration.py
Outdated
|
|
||
| def socket_handler(listener): | ||
| time.sleep(1) | ||
| sock = listener.accept()[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but this exception is not caught, meaning it'll be logged and generally treated badly. We shouldn't do anything in the background thread that we know will fail, and accept will fail here.
test/test_integration.py
Outdated
| # assert 'timed out' in e.message | ||
| pass | ||
| else: | ||
| assert False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pytest.fail, please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, i'm not familiar with pytest before, i replace it with pytest.raises or pytest.fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pytest.raises is the best thing to do if you don't plan to do anything in the except block.
test/test_integration.py
Outdated
| except (SocketTimeout, ssl.SSLError): | ||
| # Py2 raises this as a BaseSSLError, | ||
| # Py3 raises it as socket timeout. | ||
| # assert 'timed out' in e.message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably we don't need the assert statement in the comment?
test/test_integration.py
Outdated
| # assert 'timed out' in e.message | ||
| pass | ||
| else: | ||
| assert False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pytest.fail, please.
test/test_integration.py
Outdated
| except (SocketTimeout, ssl.SSLError): | ||
| # Py2 raises this as a BaseSSLError, | ||
| # Py3 raises it as socket timeout. | ||
| assert False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pytest.fail, please.
|
|
||
| send_event.wait(5) | ||
|
|
||
| assert data[0].startswith(b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry, I see that. Thanks!
hyper/common/connection.py
Outdated
| self._h1_kwargs.update(kwargs) | ||
| self._h2_kwargs.update(kwargs) | ||
|
|
||
| self._timeout = timeout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should go into _h1_kwargs and _h2_kwargs: it'll also need associated tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, it's done
|
update information: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nicely done, thank you!
[+] Add connection/read timeout for requests adapter, we can use like this: