Skip to content

Commit 74675c8

Browse files
authored
Merge pull request #13 from FlyMyAI/handle-unknown-errors
Handle unknown errors
2 parents d22fe26 + 352270f commit 74675c8

File tree

10 files changed

+323
-25
lines changed

10 files changed

+323
-25
lines changed

.github/workflows/test.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,36 @@ jobs:
5959
FMA_APIKEY: ${{ secrets.FMA_APIKEY }}
6060
run: pytest tests/test_fields.py --tb=short
6161

62+
test_unknown_error_handle:
63+
needs:
64+
- lint
65+
66+
runs-on: ubuntu-latest
67+
68+
container:
69+
image: python:3.8
70+
71+
steps:
72+
- name: Check out git repo
73+
uses: actions/checkout@v2
74+
with:
75+
fetch-depth: 0
76+
77+
- name: Fix
78+
run: git config --global --add safe.directory '*'
79+
80+
- name: Install dependencies
81+
run: pip3 install poetry pytest-asyncio && poetry config virtualenvs.create false && poetry install
82+
83+
- name: Test
84+
env:
85+
FMA_APIKEY: ${{ secrets.FMA_APIKEY }}
86+
run: pytest tests/test_unknown_error_handle.py --tb=short
87+
6288
test_flymyai_client:
6389
needs:
6490
- lint
91+
- test_unknown_error_handle
6592

6693
runs-on: ubuntu-latest
6794

@@ -88,6 +115,7 @@ jobs:
88115
test_stream:
89116
needs:
90117
- lint
118+
- test_unknown_error_handle
91119

92120
runs-on: ubuntu-latest
93121

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,4 @@ dmypy.json
142142
.idea/*
143143
poetry.lock
144144
venv*
145+
tests/fixtures*

flymyai/core/_client.py

Whitespace-only changes.

flymyai/core/_response_factory.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ def get_sse_status_code(self):
3535

3636
def _base_construct_from_sse(self):
3737
sse_status = self.get_sse_status_code()
38-
if sse_status < 400:
38+
is_details = self.sse.json().get("details") is not None
39+
if is_details and sse_status == 200:
40+
sse_status = 599
41+
if sse_status < 400 and not is_details:
3942
response = FlyMyAIResponse(
4043
status_code=sse_status,
4144
content=self.sse.data or self.sse.event,
@@ -50,7 +53,8 @@ def _base_construct_from_sse(self):
5053
status_code=sse_status,
5154
content=self.sse.data or self.sse.event,
5255
request=self.httpx_request,
53-
headers=self.httpx_response.headers or self.sse.headers,
56+
headers=self.httpx_response.headers
57+
or getattr(self.sse, "headers", {}),
5458
)
5559
)
5660

flymyai/core/_streaming.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class ServerSentEvent:
1414
_headers: dict[str, str]
1515
_url: str
1616

17+
__jsoned: Any
18+
1719
def __init__(
1820
self,
1921
*,
@@ -47,10 +49,13 @@ def data(self) -> str:
4749
return self._data
4850

4951
def json(self) -> Any:
52+
if hasattr(self, "__jsoned"):
53+
return self.__jsoned
5054
if self.data:
51-
return json.loads(self.data.strip())
55+
self.__jsoned = json.loads(self.data.strip())
5256
if self.event:
53-
return json.loads(self.event.strip())
57+
self.__jsoned = json.loads(self.event.strip())
58+
return self.__jsoned
5459

5560
@property
5661
def headers(self):

flymyai/core/clients/AsyncClient.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -99,29 +99,29 @@ async def _sse_instant(
9999
"""
100100
async with async_response_stream() as stream:
101101
sse = await SSEDecoder().aiter(stream.aiter_lines()).__anext__()
102-
response = ResponseFactory(
103-
sse=sse, httpx_request=stream.request, httpx_response=stream
104-
).construct()
105-
return response
102+
try:
103+
response = ResponseFactory(
104+
sse=sse, httpx_request=stream.request, httpx_response=stream
105+
).construct()
106+
return response
107+
except BaseFlyMyAIException as e:
108+
raise FlyMyAIPredictException.from_base_exception(e)
106109

107110
def _predict(self, client_info, payload: MultipartPayload):
108111
"""
109112
Executes request and waits for sse data
110113
:param payload: model input data
111114
:return: FlyMyAIResponse or raise an exception
112115
"""
113-
try:
114-
return self._sse_instant(
115-
lambda: self._client.stream(
116-
method="post",
117-
url=client_info.prediction_path,
118-
timeout=_predict_timeout,
119-
**payload.serialize(),
120-
headers=client_info.authorization_headers,
121-
)
116+
return self._sse_instant(
117+
lambda: self._client.stream(
118+
method="post",
119+
url=client_info.prediction_path,
120+
timeout=_predict_timeout,
121+
**payload.serialize(),
122+
headers=client_info.authorization_headers,
122123
)
123-
except BaseFlyMyAIException as e:
124-
raise FlyMyAIPredictException.from_response(e.response)
124+
)
125125

126126
async def predict(
127127
self, payload: dict, model: Optional[str] = None, max_retries=None
@@ -160,7 +160,7 @@ async def _stream(self, client_info: APIKeyClientInfo, payload: dict):
160160
httpx_response=sse_stream,
161161
).construct()
162162
except BaseFlyMyAIException as e:
163-
raise FlyMyAIPredictException.from_response(e.response)
163+
raise FlyMyAIPredictException.from_base_exception(e)
164164
yield response
165165

166166
def stream(self, payload: dict, model: Optional[str] = None, max_retries=None):

flymyai/core/clients/SyncClient.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def _predict(self, payload: MultipartPayload, client_info: APIKeyClientInfo):
6262
lambda: self._stream_iterator(client_info, payload, False)
6363
)
6464
except BaseFlyMyAIException as e:
65-
raise FlyMyAIPredictException.from_response(e.response)
65+
raise FlyMyAIPredictException.from_base_exception(e)
6666

6767
def predict(self, payload: dict, model: Optional[str] = None, max_retries=None):
6868
"""
@@ -100,7 +100,7 @@ def _stream(self, client_info: APIKeyClientInfo, payload: dict):
100100
httpx_response=sse_stream,
101101
).construct()
102102
except BaseFlyMyAIException as e:
103-
raise FlyMyAIPredictException.from_response(e.response)
103+
raise FlyMyAIPredictException.from_base_exception(e)
104104
yield response
105105

106106
def stream(self, payload: dict, model: Optional[str] = None):

flymyai/core/exceptions.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from typing import List
1+
import datetime
2+
from typing import List, Type
23

34
from ._response import FlyMyAIResponse
45
from .models.error_responses import (
@@ -32,13 +33,20 @@ def from_5xx(cls, response: FlyMyAIResponse):
3233
msg = f"""
3334
INTERNAL SERVER ERROR ({response.status_code}):
3435
REQUEST URL: {response.url};
35-
"""
36+
Content [0:250]: {response.content.decode()[0:250]}
37+
Timestamp [UTC]: {datetime.datetime.utcnow()}
38+
"""
3639
internal_error_mapping = {
3740
500: lambda: cls(msg, False, response=response),
3841
502: lambda: cls(msg, True, response=response),
3942
503: lambda: cls(msg, False, response=response),
4043
504: lambda: cls(msg, True, response=response),
4144
524: lambda: cls(msg, True, response=response),
45+
# unknown issue, probably detected on the client side
46+
599: lambda: cls(msg, False, response=response),
47+
# broker issues, they are not billed at all
48+
5000: lambda: cls(msg, False, response=response),
49+
5320: lambda: cls(msg, True, response=response),
4250
}
4351
return internal_error_mapping.get(
4452
response.status_code, lambda: cls(msg, False)
@@ -72,7 +80,10 @@ def __str__(self):
7280
return self.msg
7381

7482

75-
class FlyMyAIPredictException(BaseFlyMyAIException): ...
83+
class FlyMyAIPredictException(BaseFlyMyAIException):
84+
@classmethod
85+
def from_base_exception(cls, exception: BaseFlyMyAIException):
86+
return cls(exception.msg, exception.requires_retry, exception.response)
7687

7788

7889
class FlyMyAIOpenAPIException(BaseFlyMyAIException): ...

flymyai/utils/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ async def aretryable_callback(
4848
continue
4949
else:
5050
raise exception_group_cls(retries_history)
51+
except Exception as e:
52+
raise e
5153
else:
5254
exception_gr = exception_group_cls(retries_history)
5355
raise exception_gr

0 commit comments

Comments
 (0)