33
33
cast , Optional , Union , Any , Tuple
34
34
35
35
from cachetools import TTLCache , LRUCache
36
+ from httpx import Response
36
37
37
38
from .error import SchemaRegistryError
38
39
@@ -70,9 +71,15 @@ def __init__(self, conf: dict):
70
71
raise ValueError ("Missing required configuration property url" )
71
72
if not isinstance (base_url , string_type ):
72
73
raise TypeError ("url must be a str, not " + str (type (base_url )))
73
- if not base_url .startswith ('http' ) and not base_url .startswith ('mock' ):
74
- raise ValueError ("Invalid url {}" .format (base_url ))
75
- self .base_url = base_url .rstrip ('/' )
74
+ base_urls = []
75
+ for url in base_url .split (',' ):
76
+ url = url .strip ().rstrip ('/' )
77
+ if not url .startswith ('http' ) and not url .startswith ('mock' ):
78
+ raise ValueError ("Invalid url {}" .format (url ))
79
+ base_urls .append (url )
80
+ if not base_urls :
81
+ raise ValueError ("Missing required configuration property url" )
82
+ self .base_urls = base_urls
76
83
77
84
self .verify = True
78
85
ca = conf_copy .pop ('ssl.ca.location' , None )
@@ -93,7 +100,7 @@ def __init__(self, conf: dict):
93
100
raise ValueError ("ssl.certificate.location required when"
94
101
" configuring ssl.key.location" )
95
102
96
- parsed = urlparse (base_url )
103
+ parsed = urlparse (self . base_urls [ 0 ] )
97
104
try :
98
105
userinfo = (unquote (parsed .username ), unquote (parsed .password ))
99
106
except (AttributeError , TypeError ):
@@ -219,7 +226,7 @@ def send_request(
219
226
query : dict = None
220
227
) -> Any :
221
228
"""
222
- Sends HTTP request to the SchemaRegistry.
229
+ Sends HTTP request to the SchemaRegistry, trying each base URL in turn .
223
230
224
231
All unsuccessful attempts will raise a SchemaRegistryError with the
225
232
response contents. In most cases this will be accompanied by a
@@ -250,21 +257,22 @@ def send_request(
250
257
'Content-Type' : "application/vnd.schemaregistry.v1+json" }
251
258
252
259
response = None
253
- for i in range (self .max_retries + 1 ):
254
- response = self . session . request (
255
- method , url = "/" . join ([ self .base_url , url ]),
256
- headers = headers , data = body , params = query )
260
+ for i , base_url in enumerate (self .base_urls ):
261
+ try :
262
+ response = self .send_http_request (
263
+ base_url , url , method , headers , body , query )
257
264
258
- if (is_success (response .status_code )
259
- or not is_retriable (response .status_code )
260
- or i >= self .max_retries ):
261
- break
265
+ if is_success (response .status_code ):
266
+ return response .json ()
262
267
263
- time .sleep (full_jitter (self .retries_wait_ms , self .retries_max_wait_ms , i ) / 1000 )
268
+ if not is_retriable (response .status_code ) or i == len (self .base_urls ) - 1 :
269
+ break
270
+ except Exception as e :
271
+ if i == len (self .base_urls ) - 1 :
272
+ # Raise the exception since we have no more urls to try
273
+ raise e
264
274
265
275
try :
266
- if 200 <= response .status_code <= 299 :
267
- return response .json ()
268
276
raise SchemaRegistryError (response .status_code ,
269
277
response .json ().get ('error_code' ),
270
278
response .json ().get ('message' ))
@@ -275,6 +283,48 @@ def send_request(
275
283
"Unknown Schema Registry Error: "
276
284
+ str (response .content ))
277
285
286
+ def send_http_request (
287
+ self , base_url : str , url : str , method : str , headers : dict ,
288
+ body : Optional [str ] = None , query : dict = None
289
+ ) -> Response :
290
+ """
291
+ Sends HTTP request to the SchemaRegistry.
292
+
293
+ All unsuccessful attempts will raise a SchemaRegistryError with the
294
+ response contents. In most cases this will be accompanied by a
295
+ Schema Registry supplied error code.
296
+
297
+ In the event the response is malformed an error_code of -1 will be used.
298
+
299
+ Args:
300
+ base_url (str): Schema Registry base URL
301
+
302
+ url (str): Request path
303
+
304
+ method (str): HTTP method
305
+
306
+ headers (dict): Headers
307
+
308
+ body (str): Request content
309
+
310
+ query (dict): Query params to attach to the URL
311
+
312
+ Returns:
313
+ Response: Schema Registry response content.
314
+ """
315
+ for i in range (self .max_retries + 1 ):
316
+ response = self .session .request (
317
+ method , url = "/" .join ([base_url , url ]),
318
+ headers = headers , data = body , params = query )
319
+
320
+ if is_success (response .status_code ):
321
+ return response
322
+
323
+ if not is_retriable (response .status_code ) or i >= self .max_retries :
324
+ return response
325
+
326
+ time .sleep (full_jitter (self .retries_wait_ms , self .retries_max_wait_ms , i ) / 1000 )
327
+
278
328
279
329
def is_success (status_code : int ) -> bool :
280
330
return 200 <= status_code <= 299
@@ -495,7 +545,7 @@ class SchemaRegistryClient(object):
495
545
+------------------------------+------+-------------------------------------------------+
496
546
| Property name | type | Description |
497
547
+==============================+======+=================================================+
498
- | ``url`` * | str | Schema Registry URL. |
548
+ | ``url`` * | str | Comma-separated list of Schema Registry URLs. |
499
549
+------------------------------+------+-------------------------------------------------+
500
550
| | | Path to CA certificate file used |
501
551
| ``ssl.ca.location`` | str | to verify the Schema Registry's |
0 commit comments