|
7 | 7 | import json |
8 | 8 | import logging |
9 | 9 | import os |
10 | | -import urllib.request |
11 | | -from asyncio.tasks import Task |
| 10 | +import time |
12 | 11 | from typing import Any, Dict, List, Optional, Union |
13 | 12 |
|
14 | 13 | import aiohttp |
|
41 | 40 | ERROR_ITEMS, |
42 | 41 | ERROR_PAYLOAD, |
43 | 42 | ERRORS_KEY, |
44 | | - JOB_ID_KEY, |
45 | | - JOB_LAST_KNOWN_STATUS_KEY, |
46 | | - JOB_TYPE_KEY, |
47 | | - JOB_CREATION_TIME_KEY, |
48 | 43 | IMAGE_KEY, |
49 | 44 | IMAGE_URL_KEY, |
50 | 45 | INDEX_CONTINUOUS_ENABLE_KEY, |
51 | 46 | ITEM_METADATA_SCHEMA_KEY, |
52 | 47 | ITEMS_KEY, |
| 48 | + JOB_CREATION_TIME_KEY, |
| 49 | + JOB_ID_KEY, |
| 50 | + JOB_LAST_KNOWN_STATUS_KEY, |
| 51 | + JOB_TYPE_KEY, |
53 | 52 | KEEP_HISTORY_KEY, |
54 | 53 | MESSAGE_KEY, |
55 | 54 | MODEL_RUN_ID_KEY, |
|
63 | 62 | UPDATE_KEY, |
64 | 63 | ) |
65 | 64 | from .dataset import Dataset |
66 | | -from .dataset_item import DatasetItem, CameraParams, Quaternion |
| 65 | +from .dataset_item import CameraParams, DatasetItem, Quaternion |
67 | 66 | from .errors import ( |
68 | 67 | DatasetItemRetrievalError, |
69 | 68 | ModelCreationError, |
|
87 | 86 | PolygonPrediction, |
88 | 87 | SegmentationPrediction, |
89 | 88 | ) |
| 89 | +from .scene import Frame, LidarScene |
90 | 90 | from .slice import Slice |
91 | 91 | from .upload_response import UploadResponse |
92 | | -from .scene import Frame, LidarScene |
93 | 92 |
|
94 | 93 | # pylint: disable=E1101 |
95 | 94 | # TODO: refactor to reduce this file to under 1000 lines. |
|
105 | 104 | ) |
106 | 105 |
|
107 | 106 |
|
| 107 | +class RetryStrategy: |
| 108 | + statuses = {503, 504} |
| 109 | + sleep_times = [1, 3, 9] |
| 110 | + |
| 111 | + |
108 | 112 | class NucleusClient: |
109 | 113 | """ |
110 | 114 | Nucleus client. |
@@ -511,28 +515,41 @@ async def _make_files_request( |
511 | 515 | content_type=file[1][2], |
512 | 516 | ) |
513 | 517 |
|
514 | | - async with session.post( |
515 | | - endpoint, |
516 | | - data=form, |
517 | | - auth=aiohttp.BasicAuth(self.api_key, ""), |
518 | | - timeout=DEFAULT_NETWORK_TIMEOUT_SEC, |
519 | | - ) as response: |
520 | | - logger.info("API request has response code %s", response.status) |
521 | | - |
522 | | - try: |
523 | | - data = await response.json() |
524 | | - except aiohttp.client_exceptions.ContentTypeError: |
525 | | - # In case of 404, the server returns text |
526 | | - data = await response.text() |
527 | | - |
528 | | - if not response.ok: |
529 | | - self.handle_bad_response( |
530 | | - endpoint, |
531 | | - session.post, |
532 | | - aiohttp_response=(response.status, response.reason, data), |
| 518 | + for sleep_time in RetryStrategy.sleep_times + [-1]: |
| 519 | + async with session.post( |
| 520 | + endpoint, |
| 521 | + data=form, |
| 522 | + auth=aiohttp.BasicAuth(self.api_key, ""), |
| 523 | + timeout=DEFAULT_NETWORK_TIMEOUT_SEC, |
| 524 | + ) as response: |
| 525 | + logger.info( |
| 526 | + "API request has response code %s", response.status |
533 | 527 | ) |
534 | 528 |
|
535 | | - return data |
| 529 | + try: |
| 530 | + data = await response.json() |
| 531 | + except aiohttp.client_exceptions.ContentTypeError: |
| 532 | + # In case of 404, the server returns text |
| 533 | + data = await response.text() |
| 534 | + if ( |
| 535 | + response.status in RetryStrategy.statuses |
| 536 | + and sleep_time != -1 |
| 537 | + ): |
| 538 | + time.sleep(sleep_time) |
| 539 | + continue |
| 540 | + |
| 541 | + if not response.ok: |
| 542 | + self.handle_bad_response( |
| 543 | + endpoint, |
| 544 | + session.post, |
| 545 | + aiohttp_response=( |
| 546 | + response.status, |
| 547 | + response.reason, |
| 548 | + data, |
| 549 | + ), |
| 550 | + ) |
| 551 | + |
| 552 | + return data |
536 | 553 |
|
537 | 554 | def _process_append_requests( |
538 | 555 | self, |
@@ -1130,13 +1147,6 @@ def create_custom_index( |
1130 | 1147 | requests_command=requests.post, |
1131 | 1148 | ) |
1132 | 1149 |
|
1133 | | - def check_index_status(self, job_id: str): |
1134 | | - return self.make_request( |
1135 | | - {}, |
1136 | | - f"indexing/{job_id}", |
1137 | | - requests_command=requests.get, |
1138 | | - ) |
1139 | | - |
1140 | 1150 | def delete_custom_index(self, dataset_id: str): |
1141 | 1151 | return self.make_request( |
1142 | 1152 | {}, |
@@ -1191,14 +1201,20 @@ def make_request( |
1191 | 1201 |
|
1192 | 1202 | logger.info("Posting to %s", endpoint) |
1193 | 1203 |
|
1194 | | - response = requests_command( |
1195 | | - endpoint, |
1196 | | - json=payload, |
1197 | | - headers={"Content-Type": "application/json"}, |
1198 | | - auth=(self.api_key, ""), |
1199 | | - timeout=DEFAULT_NETWORK_TIMEOUT_SEC, |
1200 | | - ) |
1201 | | - logger.info("API request has response code %s", response.status_code) |
| 1204 | + for retry_wait_time in RetryStrategy.sleep_times: |
| 1205 | + response = requests_command( |
| 1206 | + endpoint, |
| 1207 | + json=payload, |
| 1208 | + headers={"Content-Type": "application/json"}, |
| 1209 | + auth=(self.api_key, ""), |
| 1210 | + timeout=DEFAULT_NETWORK_TIMEOUT_SEC, |
| 1211 | + ) |
| 1212 | + logger.info( |
| 1213 | + "API request has response code %s", response.status_code |
| 1214 | + ) |
| 1215 | + if response.status_code not in RetryStrategy.statuses: |
| 1216 | + break |
| 1217 | + time.sleep(retry_wait_time) |
1202 | 1218 |
|
1203 | 1219 | if not response.ok: |
1204 | 1220 | self.handle_bad_response(endpoint, requests_command, response) |
|
0 commit comments