Skip to content

Commit b118c3c

Browse files
Merge pull request #49 from nextmv-io/merschformann/fix-large-input-upload
Fixes making large input runs
2 parents 1e2ac56 + f6c90dc commit b118c3c

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

nextmv/cloud/application.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -875,11 +875,9 @@ def upload_large_input(
875875
if isinstance(input, Dict):
876876
input = json.dumps(input)
877877

878-
_ = self.client.request(
879-
method="PUT",
880-
endpoint=upload_url.upload_url,
878+
_ = self.client.upload_to_presigned_url(
879+
url=upload_url.upload_url,
881880
data=input,
882-
headers={"Content-Type": "application/json"},
883881
)
884882

885883
def upload_url(self) -> UploadURL:

nextmv/cloud/client.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,53 @@ def request(
180180

181181
return response
182182

183+
def upload_to_presigned_url(
184+
self,
185+
data: Union[Dict[str, Any], str],
186+
url: str,
187+
) -> None:
188+
"""
189+
Method to upload data to a presigned URL of the Nextmv Cloud API.
190+
Args:
191+
data: data to upload.
192+
url: URL to upload the data to.
193+
"""
194+
195+
upload_data = None
196+
if isinstance(data, Dict):
197+
upload_data = json.dumps(data, separators=(",", ":"))
198+
elif isinstance(data, str):
199+
upload_data = data
200+
else:
201+
raise ValueError("data must be a dictionary or a string")
202+
203+
session = requests.Session()
204+
retries = Retry(
205+
total=self.max_retries,
206+
backoff_factor=self.backoff_factor,
207+
backoff_jitter=self.backoff_jitter,
208+
backoff_max=self.backoff_max,
209+
status_forcelist=self.status_forcelist,
210+
allowed_methods=self.allowed_methods,
211+
)
212+
adapter = HTTPAdapter(max_retries=retries)
213+
session.mount("https://", adapter)
214+
kwargs = {
215+
"url": url,
216+
"timeout": self.timeout,
217+
"data": upload_data,
218+
}
219+
220+
response = session.put(**kwargs)
221+
222+
try:
223+
response.raise_for_status()
224+
except requests.HTTPError as e:
225+
raise requests.HTTPError(
226+
f"upload to presigned URL {url} failed with "
227+
+ f"status code {response.status_code} and message: {response.text}"
228+
) from e
229+
183230
def _set_headers_api_key(self, api_key: str) -> None:
184231
"""Sets the API key to use for requests to the Nextmv Cloud API."""
185232

@@ -202,5 +249,8 @@ def get_size(obj: Union[Dict[str, Any], IO[bytes]]) -> int:
202249
obj.seek(0) # Reset the cursor to the beginning of the file
203250
return size
204251

252+
elif isinstance(obj, str):
253+
return len(obj.encode("utf-8"))
254+
205255
else:
206256
raise TypeError("Unsupported type. Only dictionaries and file objects are supported.")

0 commit comments

Comments
 (0)