|
15 | 15 | import json |
16 | 16 | import os |
17 | 17 | import secrets |
| 18 | +import time |
18 | 19 |
|
19 | 20 | import requests |
20 | 21 | from .pgpy import PGPMessage, PGPKey |
21 | 22 | from .pgpy.constants import HashAlgorithm, SymmetricKeyAlgorithm, CompressionAlgorithm, KeyFlags |
22 | 23 |
|
| 24 | +_S3_UPLOAD_MAX_RETRIES = 6 |
| 25 | +_S3_UPLOAD_TIMEOUT_SECONDS = 120 |
| 26 | +_S3_UPLOAD_RETRY_STATUS_CODES = [408, 429, 500, 502, 503, 504] |
| 27 | + |
23 | 28 |
|
24 | 29 | def _encrypt_file_part(file, server_secret, client_secret, path=True): |
25 | 30 | """ |
@@ -193,9 +198,28 @@ def _upload_file_part_to_s3(encrypted_file_part, url): |
193 | 198 | Content-Type must NOT be specified |
194 | 199 | :param encrypted_file_part: Part of a file to upload to S3. Must not exceed 2621440 Bytes. |
195 | 200 | :param url: The S3 URL we're uploading to |
196 | | - :return: The JSON response from S3. |
| 201 | + :return: The response from S3 once the part has been accepted. |
| 202 | + :raises requests.exceptions.RequestException: If the part still cannot be uploaded after retries. |
197 | 203 | """ |
198 | | - return requests.put(url=url, data=encrypted_file_part) |
| 204 | + last_exception = None |
| 205 | + for retries in range(_S3_UPLOAD_MAX_RETRIES): |
| 206 | + try: |
| 207 | + response = requests.put(url=url, data=encrypted_file_part, timeout=_S3_UPLOAD_TIMEOUT_SECONDS) |
| 208 | + except requests.exceptions.RequestException as e: |
| 209 | + last_exception = e |
| 210 | + else: |
| 211 | + if response.status_code not in _S3_UPLOAD_RETRY_STATUS_CODES: |
| 212 | + response.raise_for_status() |
| 213 | + return response |
| 214 | + last_exception = requests.exceptions.HTTPError( |
| 215 | + "S3 returned retryable failure status %d" % response.status_code, response=response |
| 216 | + ) |
| 217 | + |
| 218 | + if retries == _S3_UPLOAD_MAX_RETRIES - 1: |
| 219 | + break |
| 220 | + time.sleep(2 ** retries) |
| 221 | + |
| 222 | + raise last_exception |
199 | 223 |
|
200 | 224 |
|
201 | 225 | def _calculate_package_checksum(package_code, keycode): |
|
0 commit comments