9
9
import time
10
10
import typing
11
11
from contextlib import asynccontextmanager , contextmanager
12
+ from dataclasses import dataclass
12
13
from typing import Any , Callable , ClassVar , Literal , TypeVar
13
14
14
15
import httpx
17
18
import fal .api
18
19
from fal ._serialization import include_modules_from
19
20
from fal .api import RouteSignature
20
- from fal .exceptions import RequestCancelledException
21
+ from fal .exceptions import FalServerlessException , RequestCancelledException
21
22
from fal .logging import get_logger
22
23
from fal .toolkit .file import get_lifecycle_preference
23
24
from fal .toolkit .file .providers .fal import GLOBAL_LIFECYCLE_PREFERENCE
@@ -76,6 +77,12 @@ def initialize_and_serve():
76
77
return fn
77
78
78
79
80
+ @dataclass
81
+ class AppClientError (FalServerlessException ):
82
+ message : str
83
+ status_code : int
84
+
85
+
79
86
class EndpointClient :
80
87
def __init__ (self , url , endpoint , signature , timeout : int | None = None ):
81
88
self .url = url
@@ -88,17 +95,19 @@ def __init__(self, url, endpoint, signature, timeout: int | None = None):
88
95
89
96
def __call__ (self , data ):
90
97
with httpx .Client () as client :
98
+ url = self .url + self .signature .path
91
99
resp = client .post (
92
100
self .url + self .signature .path ,
93
101
json = data .dict () if hasattr (data , "dict" ) else dict (data ),
94
102
timeout = self .timeout ,
95
103
)
96
- try :
97
- resp .raise_for_status ()
98
- except httpx .HTTPStatusError :
104
+ if not resp .is_success :
99
105
# allow logs to be printed before raising the exception
100
106
time .sleep (1 )
101
- raise
107
+ raise AppClientError (
108
+ f"Failed to POST { url } : { resp .status_code } { resp .text } " ,
109
+ status_code = resp .status_code ,
110
+ )
102
111
resp_dict = resp .json ()
103
112
104
113
if not self .return_type :
@@ -151,12 +160,16 @@ def _print_logs():
151
160
with httpx .Client () as client :
152
161
retries = 100
153
162
for _ in range (retries ):
154
- resp = client .get (info .url + "/health" , timeout = 60 )
163
+ url = info .url + "/health"
164
+ resp = client .get (url , timeout = 60 )
155
165
156
166
if resp .is_success :
157
167
break
158
168
elif resp .status_code not in (500 , 404 ):
159
- resp .raise_for_status ()
169
+ raise AppClientError (
170
+ f"Failed to GET { url } : { resp .status_code } { resp .text } " ,
171
+ status_code = resp .status_code ,
172
+ )
160
173
time .sleep (0.1 )
161
174
162
175
client = cls (app_cls , info .url )
0 commit comments