Skip to content
This repository has been archived by the owner on Sep 3, 2022. It is now read-only.

Commit

Permalink
Use http Keep-Alive, else BigQuery queries are ~seconds slower than n…
Browse files Browse the repository at this point in the history
…ecessary (#195)

- Before (without Keep-Alive): ~3-7s for BigQuery `select 3` with an already cached result
- After (with Keep-Alive): ~1.5-3s
- Query sends these 6 http requests and runtime appears to be dominated by network RTT
  • Loading branch information
jdanbrown authored and yebrahim committed Feb 14, 2017
1 parent 62716e9 commit 7ff0b3c
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 17 deletions.
21 changes: 12 additions & 9 deletions datalab/utils/_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ class Http(object):
"""A helper class for making HTTP requests.
"""

# Reuse one Http object across requests to take advantage of Keep-Alive, e.g.
# for BigQuery queries that requires at least ~5 sequential http requests.
#
# TODO(nikhilko):
# SSL cert validation seemingly fails, and workarounds are not amenable
# to implementing in library code. So configure the Http object to skip
# doing so, in the interim.
http = httplib2.Http()
http.disable_ssl_certificate_validation = True

def __init__(self):
pass

Expand Down Expand Up @@ -109,15 +119,8 @@ def request(url, args=None, data=None, headers=None, method=None,
if method is None:
method = 'GET'

# Create an Http object to issue requests. Associate the credentials
# with it if specified to perform authorization.
#
# TODO(nikhilko):
# SSL cert validation seemingly fails, and workarounds are not amenable
# to implementing in library code. So configure the Http object to skip
# doing so, in the interim.
http = httplib2.Http()
http.disable_ssl_certificate_validation = True
# Authorize with credentials if given.
http = Http.http
if credentials is not None:
http = credentials.authorize(http)
if stats is not None:
Expand Down
16 changes: 8 additions & 8 deletions tests/_util/http_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
class TestCases(unittest.TestCase):

@mock.patch('httplib2.Response')
@mock.patch('httplib2.Http.request')
@mock.patch('datalab.utils._http.Http.http.request')
def test_get_request_is_invoked(self, mock_request, mock_response):
TestCases._setup_mocks(mock_request, mock_response, '{}')

Expand All @@ -32,23 +32,23 @@ def test_get_request_is_invoked(self, mock_request, mock_response):
self.assertEqual(mock_request.call_args[1]['method'], 'GET')

@mock.patch('httplib2.Response')
@mock.patch('httplib2.Http.request')
@mock.patch('datalab.utils._http.Http.http.request')
def test_post_request_is_invoked(self, mock_request, mock_response):
TestCases._setup_mocks(mock_request, mock_response, '{}')

Http.request('http://www.example.org', data={})
self.assertEqual(mock_request.call_args[1]['method'], 'POST')

@mock.patch('httplib2.Response')
@mock.patch('httplib2.Http.request')
@mock.patch('datalab.utils._http.Http.http.request')
def test_explicit_post_request_is_invoked(self, mock_request, mock_response):
TestCases._setup_mocks(mock_request, mock_response, '{}')

Http.request('http://www.example.org', method='POST')
self.assertEqual(mock_request.call_args[1]['method'], 'POST')

@mock.patch('httplib2.Response')
@mock.patch('httplib2.Http.request')
@mock.patch('datalab.utils._http.Http.http.request')
def test_query_string_format(self, mock_request, mock_response):
TestCases._setup_mocks(mock_request, mock_response, '{}')

Expand All @@ -59,7 +59,7 @@ def test_query_string_format(self, mock_request, mock_response):
self.assertTrue('b=a+b+c' in parts[1:])

@mock.patch('httplib2.Response')
@mock.patch('httplib2.Http.request')
@mock.patch('datalab.utils._http.Http.http.request')
def test_formats_json_request(self, mock_request, mock_response):
TestCases._setup_mocks(mock_request, mock_response, '{}')

Expand All @@ -71,7 +71,7 @@ def test_formats_json_request(self, mock_request, mock_response):
'application/json')

@mock.patch('httplib2.Response')
@mock.patch('httplib2.Http.request')
@mock.patch('datalab.utils._http.Http.http.request')
def test_supports_custom_content(self, mock_request, mock_response):
TestCases._setup_mocks(mock_request, mock_response, '{}')

Expand All @@ -83,15 +83,15 @@ def test_supports_custom_content(self, mock_request, mock_response):
self.assertEqual(mock_request.call_args[1]['headers']['Content-Type'], 'text/plain')

@mock.patch('httplib2.Response')
@mock.patch('httplib2.Http.request')
@mock.patch('datalab.utils._http.Http.http.request')
def test_parses_json_response(self, mock_request, mock_response):
TestCases._setup_mocks(mock_request, mock_response, '{"abc":123}')

data = Http.request('http://www.example.org')
self.assertEqual(data['abc'], 123)

@mock.patch('httplib2.Response')
@mock.patch('httplib2.Http.request')
@mock.patch('datalab.utils._http.Http.http.request')
def test_raises_http_error(self, mock_request, mock_response):
TestCases._setup_mocks(mock_request, mock_response, 'Not Found', 404)

Expand Down

0 comments on commit 7ff0b3c

Please sign in to comment.