Skip to content

Instantly share code, notes, and snippets.

@medmunds
Created September 21, 2018 00:48
Show Gist options
  • Save medmunds/ad47a5001729040d7743ae20d32786e1 to your computer and use it in GitHub Desktop.
Save medmunds/ad47a5001729040d7743ae20d32786e1 to your computer and use it in GitHub Desktop.
Monkey-patch botocore to improve performance on large API requests
# Monkeypatch botocore.awsrequest.AWSRequest.body to improve performance by caching result.
# Usage: import this file once, at some point before making boto3 requests
# See https://github.com/boto/botocore/issues/1561
import six
from botocore.awsrequest import AWSRequest
# Monkeypatch AWSRequest.body to improve performance by caching result.
# - AWSRequest.body is accessed multiple times during request signing.
# (See also https://github.com/boto/botocore/pull/1478.)
# - AWSPreparedRequest.prepare_body uses urlencode, which is lengthy on large strings
# (specifically quote_plus/quote_from_bytes).
# - The botocore 1.12.3 AWSRequest.body implementation needlessly runs prepare_body
# twice in a row (because AWSPreparedRequest.__init__ also calls prepare_body).
def request_body(self):
if not hasattr(self, "_cached_body") or self.data != self._cached_body_data:
body = self.prepare().body
if isinstance(body, six.text_type):
body = body.encode('utf-8')
# Note: if self.data is mutable (e.g., POST data dict), this could conceivably
# miss changes to the data and return a stale body. As a practical matter,
# though, the only botocore code that modifies AWSRequest.data after creation is
# auth.SigV4QueryAuth, which might replace a data dict with an empty string.
# (So there's no need to implement more robust--and expensive--caching here.)
self._cached_body_data = self.data
self._cached_body = body
return self._cached_body
setattr(AWSRequest, "body", property(request_body))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment