11import logging
22import types
33import grpc
4+ from grpc import ClientCallDetails
45from google .protobuf .json_format import ParseDict
56from google .protobuf .message_factory import MessageFactory # , GetMessageClass
67from google .protobuf .descriptor_pool import DescriptorPool
1516_LOGGER = logging .getLogger (__name__ )
1617
1718
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+
1828class _ClientInterceptor (
1929 grpc .UnaryUnaryClientInterceptor ,
2030 grpc .UnaryStreamClientInterceptor ,
2131 grpc .StreamUnaryClientInterceptor ,
2232 grpc .StreamStreamClientInterceptor ,
2333):
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+ ):
2537 self ._request_map = request_map
2638 self ._channel_key = channel_key
2739 self .metadata = options .get ("metadata" , {})
40+ self .timeout = timeout or 60
2841
2942 def _check_message (self , client_call_details , request_or_iterator , is_stream ):
3043 if client_call_details .method in self ._request_map :
@@ -123,18 +136,27 @@ def _retry_call(
123136 return response_or_iterator
124137
125138 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+ ):
127146 if retries >= _MAX_RETRIES :
128147 channel = e .meta .get ("channel" )
129148 if channel in _GRPC_CHANNEL :
130149 _LOGGER .error (
131150 f"Disconnect gRPC Endpoint. (channel = { channel } )"
132151 )
133152 del _GRPC_CHANNEL [channel ]
153+
154+ if e .status_code == "DEADLINE_EXCEEDED" :
155+ raise ERROR_GRPC_TIMEOUT ()
134156 raise e
135157 else :
136158 _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 } "
138160 )
139161 else :
140162 raise e
@@ -160,9 +182,20 @@ def _intercept_call(
160182 is_response_stream ,
161183 )
162184
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+
163194 def intercept_unary_unary (self , continuation , client_call_details , request ):
195+ new_call_details = self ._create_new_call_details (client_call_details )
196+
164197 return self ._intercept_call (
165- continuation , client_call_details , request , False , False
198+ continuation , new_call_details , request , False , False
166199 )
167200
168201 def intercept_unary_stream (self , continuation , client_call_details , request ):
@@ -263,7 +296,7 @@ def _bind_grpc_method(
263296
264297
265298class GRPCClient (object ):
266- def __init__ (self , channel , options , channel_key ):
299+ def __init__ (self , channel , options , channel_key , timeout = None ):
267300 self ._request_map = {}
268301 self ._api_resources = {}
269302
@@ -272,7 +305,7 @@ def __init__(self, channel, options, channel_key):
272305 self ._init_grpc_reflection ()
273306
274307 _client_interceptor = _ClientInterceptor (
275- options , channel_key , self ._request_map
308+ options , channel_key , self ._request_map , timeout
276309 )
277310 _intercept_channel = grpc .intercept_channel (channel , _client_interceptor )
278311 self ._bind_grpc_stub (_intercept_channel )
@@ -326,7 +359,13 @@ def _create_insecure_channel(endpoint, options):
326359 return grpc .insecure_channel (endpoint , options = options )
327360
328361
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+ ):
330369 if endpoint is None :
331370 raise Exception ("Client's endpoint is undefined." )
332371
@@ -350,7 +389,9 @@ def client(endpoint=None, ssl_enabled=False, max_message_length=None, **client_o
350389 )
351390
352391 try :
353- _GRPC_CHANNEL [endpoint ] = GRPCClient (channel , client_opts , endpoint )
392+ _GRPC_CHANNEL [endpoint ] = GRPCClient (
393+ channel , client_opts , endpoint , timeout
394+ )
354395 except Exception as e :
355396 if hasattr (e , "details" ):
356397 raise ERROR_GRPC_CONNECTION (channel = endpoint , message = e .details ())
0 commit comments