|
7 | 7 | from typing import Final, Literal |
8 | 8 | from uuid import UUID |
9 | 9 |
|
10 | | -from fastapi import FastAPI, HTTPException, status |
| 10 | +from fastapi import FastAPI |
11 | 11 | from fastapi.encoders import jsonable_encoder |
12 | 12 | from models_library.api_schemas_storage.storage_schemas import ( |
13 | 13 | ETag, |
|
29 | 29 | from models_library.rest_pagination import PageLimitInt, PageOffsetInt |
30 | 30 | from pydantic import AnyUrl |
31 | 31 | from settings_library.tracing import TracingSettings |
| 32 | +from simcore_service_api_server.exceptions.backend_errors import BackendTimeoutError |
32 | 33 | from simcore_service_api_server.models.schemas.files import UserFile |
33 | 34 | from simcore_service_api_server.models.schemas.jobs import UserFileToProgramJob |
34 | 35 | from tenacity import ( |
35 | 36 | AsyncRetrying, |
| 37 | + TryAgain, |
36 | 38 | before_sleep_log, |
37 | 39 | retry_if_exception_type, |
38 | 40 | stop_after_delay, |
@@ -210,36 +212,34 @@ async def complete_file_upload(self, *, user_id: int, file: File) -> ETag: |
210 | 212 | ].model_validate_json(response.text) |
211 | 213 | assert file_upload_complete_response.data # nosec |
212 | 214 | state_url = f"{file_upload_complete_response.data.links.state}" |
213 | | - async for attempt in AsyncRetrying( |
214 | | - reraise=False, |
215 | | - wait=wait_fixed(1), |
216 | | - stop=stop_after_delay(_POLL_TIMEOUT), |
217 | | - retry=retry_if_exception_type(ValueError), |
218 | | - before_sleep=before_sleep_log(_logger, logging.DEBUG), |
219 | | - ): |
220 | | - with attempt: |
221 | | - resp = await self.client.post(state_url) |
222 | | - resp.raise_for_status() |
223 | | - future_enveloped = Envelope[ |
224 | | - FileUploadCompleteFutureResponse |
225 | | - ].model_validate_json(resp.text) |
226 | | - assert future_enveloped.data # nosec |
227 | | - if future_enveloped.data.state == FileUploadCompleteState.NOK: |
228 | | - msg = "upload not ready yet" |
229 | | - raise ValueError(msg) |
230 | | - |
231 | | - assert future_enveloped.data.e_tag # nosec |
232 | | - _logger.debug( |
233 | | - "multipart upload completed in %s, received %s", |
234 | | - attempt.retry_state.retry_object.statistics, |
235 | | - f"{future_enveloped.data.e_tag=}", |
236 | | - ) |
237 | | - return future_enveloped.data.e_tag |
238 | | - msg = f"Could not complete the upload for file '{file.filename}' (id: {file.id}) within the allocated time." |
239 | | - raise HTTPException( |
240 | | - status_code=status.HTTP_504_GATEWAY_TIMEOUT, |
241 | | - detail=msg, |
242 | | - ) |
| 215 | + try: |
| 216 | + async for attempt in AsyncRetrying( |
| 217 | + reraise=True, |
| 218 | + wait=wait_fixed(1), |
| 219 | + stop=stop_after_delay(_POLL_TIMEOUT), |
| 220 | + retry=retry_if_exception_type(TryAgain), |
| 221 | + before_sleep=before_sleep_log(_logger, logging.DEBUG), |
| 222 | + ): |
| 223 | + with attempt: |
| 224 | + resp = await self.client.post(state_url) |
| 225 | + resp.raise_for_status() |
| 226 | + future_enveloped = Envelope[ |
| 227 | + FileUploadCompleteFutureResponse |
| 228 | + ].model_validate_json(resp.text) |
| 229 | + assert future_enveloped.data # nosec |
| 230 | + if future_enveloped.data.state == FileUploadCompleteState.NOK: |
| 231 | + msg = "upload not ready yet" |
| 232 | + raise TryAgain() |
| 233 | + |
| 234 | + assert future_enveloped.data.e_tag # nosec |
| 235 | + _logger.debug( |
| 236 | + "multipart upload completed in %s, received %s", |
| 237 | + attempt.retry_state.retry_object.statistics, |
| 238 | + f"{future_enveloped.data.e_tag=}", |
| 239 | + ) |
| 240 | + return future_enveloped.data.e_tag |
| 241 | + except TryAgain as exc: |
| 242 | + raise BackendTimeoutError() from exc |
243 | 243 |
|
244 | 244 | @_exception_mapper(http_status_map={}) |
245 | 245 | async def abort_file_upload(self, *, user_id: int, file: File) -> None: |
|
0 commit comments