1
1
import logging
2
2
import types
3
3
import grpc
4
+ from grpc import ClientCallDetails
4
5
from google .protobuf .json_format import ParseDict
5
6
from google .protobuf .message_factory import MessageFactory # , GetMessageClass
6
7
from google .protobuf .descriptor_pool import DescriptorPool
15
16
_LOGGER = logging .getLogger (__name__ )
16
17
17
18
19
+ class _ClientCallDetails (ClientCallDetails ):
20
+ def __init__ (self , method , timeout , metadata , credentials , wait_for_ready ):
21
+ self .method = method
22
+ self .timeout = timeout
23
+ self .metadata = metadata
24
+ self .credentials = credentials
25
+ self .wait_for_ready = wait_for_ready
26
+
27
+
18
28
class _ClientInterceptor (
19
29
grpc .UnaryUnaryClientInterceptor ,
20
30
grpc .UnaryStreamClientInterceptor ,
21
31
grpc .StreamUnaryClientInterceptor ,
22
32
grpc .StreamStreamClientInterceptor ,
23
33
):
24
- def __init__ (self , options : dict , channel_key : str , request_map : dict ):
34
+ def __init__ (
35
+ self , options : dict , channel_key : str , request_map : dict , timeout : int = None
36
+ ):
25
37
self ._request_map = request_map
26
38
self ._channel_key = channel_key
27
39
self .metadata = options .get ("metadata" , {})
40
+ self .timeout = timeout or 60
28
41
29
42
def _check_message (self , client_call_details , request_or_iterator , is_stream ):
30
43
if client_call_details .method in self ._request_map :
@@ -123,18 +136,27 @@ def _retry_call(
123
136
return response_or_iterator
124
137
125
138
except Exception as e :
126
- if e .error_code == "ERROR_GRPC_CONNECTION" :
139
+ if not isinstance (e , ERROR_BASE ):
140
+ e = ERROR_UNKNOWN (message = str (e ))
141
+
142
+ if (
143
+ e .error_code == "ERROR_GRPC_CONNECTION"
144
+ or e .status_code == "DEADLINE_EXCEEDED"
145
+ ):
127
146
if retries >= _MAX_RETRIES :
128
147
channel = e .meta .get ("channel" )
129
148
if channel in _GRPC_CHANNEL :
130
149
_LOGGER .error (
131
150
f"Disconnect gRPC Endpoint. (channel = { channel } )"
132
151
)
133
152
del _GRPC_CHANNEL [channel ]
153
+
154
+ if e .status_code == "DEADLINE_EXCEEDED" :
155
+ raise ERROR_GRPC_TIMEOUT ()
134
156
raise e
135
157
else :
136
158
_LOGGER .debug (
137
- f"Retry gRPC Call: reason = { e .message } , retry = { retries + 1 } "
159
+ f"Retry gRPC Call: method = { client_call_details . method } , reason = { e .message } , retry = { retries + 1 } "
138
160
)
139
161
else :
140
162
raise e
@@ -160,9 +182,20 @@ def _intercept_call(
160
182
is_response_stream ,
161
183
)
162
184
185
+ def _create_new_call_details (self , client_call_details ):
186
+ return _ClientCallDetails (
187
+ method = client_call_details .method ,
188
+ timeout = self .timeout ,
189
+ metadata = client_call_details .metadata ,
190
+ credentials = client_call_details .credentials ,
191
+ wait_for_ready = client_call_details .wait_for_ready ,
192
+ )
193
+
163
194
def intercept_unary_unary (self , continuation , client_call_details , request ):
195
+ new_call_details = self ._create_new_call_details (client_call_details )
196
+
164
197
return self ._intercept_call (
165
- continuation , client_call_details , request , False , False
198
+ continuation , new_call_details , request , False , False
166
199
)
167
200
168
201
def intercept_unary_stream (self , continuation , client_call_details , request ):
@@ -263,7 +296,7 @@ def _bind_grpc_method(
263
296
264
297
265
298
class GRPCClient (object ):
266
- def __init__ (self , channel , options , channel_key ):
299
+ def __init__ (self , channel , options , channel_key , timeout = None ):
267
300
self ._request_map = {}
268
301
self ._api_resources = {}
269
302
@@ -272,7 +305,7 @@ def __init__(self, channel, options, channel_key):
272
305
self ._init_grpc_reflection ()
273
306
274
307
_client_interceptor = _ClientInterceptor (
275
- options , channel_key , self ._request_map
308
+ options , channel_key , self ._request_map , timeout
276
309
)
277
310
_intercept_channel = grpc .intercept_channel (channel , _client_interceptor )
278
311
self ._bind_grpc_stub (_intercept_channel )
@@ -326,7 +359,13 @@ def _create_insecure_channel(endpoint, options):
326
359
return grpc .insecure_channel (endpoint , options = options )
327
360
328
361
329
- def client (endpoint = None , ssl_enabled = False , max_message_length = None , ** client_opts ):
362
+ def client (
363
+ endpoint = None ,
364
+ ssl_enabled = False ,
365
+ max_message_length = None ,
366
+ timeout = None ,
367
+ ** client_opts ,
368
+ ):
330
369
if endpoint is None :
331
370
raise Exception ("Client's endpoint is undefined." )
332
371
@@ -350,7 +389,9 @@ def client(endpoint=None, ssl_enabled=False, max_message_length=None, **client_o
350
389
)
351
390
352
391
try :
353
- _GRPC_CHANNEL [endpoint ] = GRPCClient (channel , client_opts , endpoint )
392
+ _GRPC_CHANNEL [endpoint ] = GRPCClient (
393
+ channel , client_opts , endpoint , timeout
394
+ )
354
395
except Exception as e :
355
396
if hasattr (e , "details" ):
356
397
raise ERROR_GRPC_CONNECTION (channel = endpoint , message = e .details ())
0 commit comments