Skip to content

Commit b9b4796

Browse files
authored
Fix retry arg and improve retry strategy (#362)
1 parent e0d53e8 commit b9b4796

File tree

5 files changed

+63
-27
lines changed

5 files changed

+63
-27
lines changed

roboflow/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from roboflow.models import CLIPModel, GazeModel # noqa: F401
1616
from roboflow.util.general import write_line
1717

18-
__version__ = "1.1.54"
18+
__version__ = "1.1.55"
1919

2020

2121
def check_key(api_key, model, notebook, num_retries=0):

roboflow/adapters/rfapi.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import Optional
55

66
import requests
7+
from requests.exceptions import RequestException
78
from requests_toolbelt.multipart.encoder import MultipartEncoder
89

910
from roboflow.config import API_URL, DEFAULT_BATCH_NAME, DEFAULT_JOB_NAME
@@ -26,6 +27,7 @@ class AnnotationSaveError(RoboflowError):
2627
def __init__(self, message, status_code=None):
2728
self.message = message
2829
self.status_code = status_code
30+
self.retries = 0
2931
super().__init__(self.message)
3032

3133

@@ -85,14 +87,21 @@ def upload_image(
8587
"file": ("imageToUpload", imgjpeg, "image/jpeg"),
8688
}
8789
)
88-
response = requests.post(upload_url, data=m, headers={"Content-Type": m.content_type}, timeout=(300, 300))
90+
91+
try:
92+
response = requests.post(upload_url, data=m, headers={"Content-Type": m.content_type}, timeout=(300, 300))
93+
except RequestException as e:
94+
raise ImageUploadError(str(e)) from e
8995

9096
else:
9197
# Hosted image upload url
9298
upload_url = _hosted_upload_url(api_key, project_url, image_path, split, coalesced_batch_name, tag_names)
9399

94-
# Get response
95-
response = requests.post(upload_url, timeout=(300, 300))
100+
try:
101+
# Get response
102+
response = requests.post(upload_url, timeout=(300, 300))
103+
except RequestException as e:
104+
raise ImageUploadError(str(e)) from e
96105

97106
responsejson = None
98107
try:
@@ -147,12 +156,15 @@ def save_annotation(
147156
api_key, project_url, annotation_name, image_id, job_name, is_prediction, overwrite
148157
)
149158

150-
response = requests.post(
151-
upload_url,
152-
data=json.dumps({"annotationFile": annotation_string, "labelmap": annotation_labelmap}),
153-
headers={"Content-Type": "application/json"},
154-
timeout=(60, 60),
155-
)
159+
try:
160+
response = requests.post(
161+
upload_url,
162+
data=json.dumps({"annotationFile": annotation_string, "labelmap": annotation_labelmap}),
163+
headers={"Content-Type": "application/json"},
164+
timeout=(60, 60),
165+
)
166+
except RequestException as e:
167+
raise AnnotationSaveError(str(e)) from e
156168

157169
# Handle response
158170
responsejson = None

roboflow/core/project.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import requests
1212

1313
from roboflow.adapters import rfapi
14-
from roboflow.adapters.rfapi import ImageUploadError
14+
from roboflow.adapters.rfapi import AnnotationSaveError, ImageUploadError
1515
from roboflow.config import API_URL, DEMO_KEYS
1616
from roboflow.core.version import Version
1717
from roboflow.util.general import Retry
@@ -515,26 +515,34 @@ def save_annotation(
515515
job_name=None,
516516
is_prediction: bool = False,
517517
annotation_overwrite=False,
518+
num_retry_uploads=0,
518519
):
519520
project_url = self.id.rsplit("/")[1]
520521
annotation_name, annotation_str = self._annotation_params(annotation_path)
521522
t0 = time.time()
523+
upload_retry_attempts = 0
524+
retry = Retry(num_retry_uploads, AnnotationSaveError)
522525

523-
annotation = rfapi.save_annotation(
524-
self.__api_key,
525-
project_url,
526-
annotation_name, # type: ignore[type-var]
527-
annotation_str, # type: ignore[type-var]
528-
image_id,
529-
job_name=job_name, # type: ignore[type-var]
530-
is_prediction=is_prediction,
531-
annotation_labelmap=annotation_labelmap,
532-
overwrite=annotation_overwrite,
533-
)
526+
try:
527+
annotation = rfapi.save_annotation(
528+
self.__api_key,
529+
project_url,
530+
annotation_name, # type: ignore[type-var]
531+
annotation_str, # type: ignore[type-var]
532+
image_id,
533+
job_name=job_name, # type: ignore[type-var]
534+
is_prediction=is_prediction,
535+
annotation_labelmap=annotation_labelmap,
536+
overwrite=annotation_overwrite,
537+
)
538+
upload_retry_attempts = retry.retries
539+
except AnnotationSaveError as e:
540+
e.retries = upload_retry_attempts
541+
raise
534542

535543
upload_time = time.time() - t0
536544

537-
return annotation, upload_time
545+
return annotation, upload_time, upload_retry_attempts
538546

539547
def single_upload(
540548
self,
@@ -563,6 +571,7 @@ def single_upload(
563571
uploaded_image, uploaded_annotation = None, None
564572
upload_time, annotation_time = None, None
565573
upload_retry_attempts = 0
574+
annotation_upload_retry_attempts = 0
566575

567576
if image_path:
568577
uploaded_image, upload_time, upload_retry_attempts = self.upload_image(
@@ -579,13 +588,14 @@ def single_upload(
579588
image_id = uploaded_image["id"] # type: ignore[index]
580589

581590
if annotation_path and image_id:
582-
uploaded_annotation, annotation_time = self.save_annotation(
591+
uploaded_annotation, annotation_time, annotation_upload_retry_attempts = self.save_annotation(
583592
annotation_path,
584593
annotation_labelmap,
585594
image_id,
586595
batch_name,
587596
is_prediction,
588597
annotation_overwrite,
598+
num_retry_uploads=num_retry_uploads,
589599
)
590600

591601
return {
@@ -594,6 +604,7 @@ def single_upload(
594604
"upload_time": upload_time,
595605
"annotation_time": annotation_time,
596606
"upload_retry_attempts": upload_retry_attempts,
607+
"annotation_upload_retry_attempts": annotation_upload_retry_attempts,
597608
}
598609

599610
def _annotation_params(self, annotation_path):

roboflow/core/workspace.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ def _upload_image(imagedesc):
349349
batch_name=batch_name,
350350
sequence_number=imagedesc.get("index"),
351351
sequence_size=len(images),
352+
num_retry_uploads=num_retries,
352353
)
353354

354355
return image, upload_time, upload_retry_attempts
@@ -376,6 +377,7 @@ def _save_annotation(image_id, imagedesc):
376377
annotation_labelmap=labelmap,
377378
image_id=image_id,
378379
job_name=batch_name,
380+
num_retry_uploads=num_retries,
379381
)
380382

381383
return annotation, upload_time

roboflow/util/general.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import sys
2+
import time
3+
from random import random
24

35

46
def write_line(line):
@@ -13,8 +15,16 @@ def __init__(self, max_retries, retry_on):
1315
self.retry_on = retry_on
1416
self.retries = 0
1517

18+
def backoff(self):
19+
"""
20+
Backoff for a random time based on number of retries.
21+
"""
22+
base_t_ms = 100
23+
max_t_ms = 30000
24+
sleep_ms = random() * min(max_t_ms, base_t_ms * 2**self.retries)
25+
time.sleep(int(sleep_ms) / 1000)
26+
1627
def __call__(self, func, *args, **kwargs):
17-
self.retries = 0
1828
retry_on = self.retry_on
1929
if not retry_on:
2030
retry_on = (Exception,)
@@ -24,8 +34,9 @@ def __call__(self, func, *args, **kwargs):
2434
return func(*args, **kwargs)
2535
except BaseException as e:
2636
if isinstance(e, retry_on):
27-
self.retries += 1
28-
if self.retries > self.max_retries:
37+
if self.retries >= self.max_retries:
2938
raise
39+
self.backoff()
40+
self.retries += 1
3041
else:
3142
raise

0 commit comments

Comments
 (0)