33import time
44
55import requests
6- from .exceptions import (ObjectAlreadyExists ,
6+ from .exceptions import (HTTPStatus0Error , ObjectAlreadyExists ,
77 ObjectNotFound , ObjectUnprocessable ,
88 RequestMalformed , RequestUnauthorized ,
99 ServerError , ServiceUnavailable , TypesenseClientError )
@@ -17,10 +17,9 @@ def __init__(self, config):
1717 self .nodes = copy .deepcopy (self .config .nodes )
1818 self .node_index = 0
1919
20- @staticmethod
21- def check_failed_node (node , healthcheck_interval ):
20+ def check_failed_node (self , node ):
2221 current_epoch_ts = int (time .time ())
23- return (( current_epoch_ts - node .last_access_ts ) > healthcheck_interval )
22+ return (current_epoch_ts - node .last_access_ts ) > self . config . healthcheck_interval_seconds
2423
2524 # Returns a healthy host from the pool in a round-robin fashion.
2625 # Might return an unhealthy host periodically to check for recovery.
@@ -30,19 +29,19 @@ def get_node(self):
3029 i += 1
3130 node = self .nodes [self .node_index ]
3231 self .node_index = (self .node_index + 1 ) % len (self .nodes )
33- healthcheck_interval = self .config .healthcheck_interval_seconds
3432
35- if node .healthy or ApiCall .check_failed_node (node , healthcheck_interval ):
33+ if node .healthy or self .check_failed_node (node ):
3634 return node
3735
3836 # None of the nodes are marked healthy, but some of them could have become healthy since last health check.
3937 # So we will just return the next node.
40- self .node_index = (self .node_index + 1 ) % len (self .nodes )
4138 return self .nodes [self .node_index ]
4239
4340 @staticmethod
4441 def get_exception (http_code ):
45- if http_code == 400 :
42+ if http_code == 0 :
43+ return HTTPStatus0Error
44+ elif http_code == 400 :
4645 return RequestMalformed
4746 elif http_code == 401 :
4847 return RequestUnauthorized
@@ -62,6 +61,8 @@ def get_exception(http_code):
6261 # Makes the actual http request, along with retries
6362 def make_request (self , fn , endpoint , as_json , ** kwargs ):
6463 num_tries = 0
64+ last_exception = None
65+
6566 while num_tries < (self .config .num_retries + 1 ):
6667 num_tries += 1
6768 node = self .get_node ()
@@ -86,19 +87,18 @@ def make_request(self, fn, endpoint, as_json, **kwargs):
8687 # We should raise a custom exception if status code is not 200 or 201
8788 if r .status_code not in [200 , 201 ]:
8889 error_message = r .json ().get ('message' , 'API error.' )
89- # print('error_message: ' + error_message)
90+ # Raised exception will be caught and retried only if it's a 50X
9091 raise ApiCall .get_exception (r .status_code )(r .status_code , error_message )
9192
9293 return r .json () if as_json else r .text
9394 except (requests .exceptions .Timeout , requests .exceptions .ConnectionError , requests .exceptions .HTTPError ,
94- requests .exceptions .RequestException , requests .exceptions .SSLError ):
95+ requests .exceptions .RequestException , requests .exceptions .SSLError ,
96+ HTTPStatus0Error , ServerError , ServiceUnavailable ) as e :
9597 # Catch the exception and retry
96- pass
97-
98- # print('Failed, retrying after sleep: ' + node.port)
99- time .sleep (self .config .retry_interval_seconds )
98+ last_exception = e
99+ time .sleep (self .config .retry_interval_seconds )
100100
101- raise TypesenseClientError ( 'Retries exceeded.' )
101+ raise last_exception
102102
103103 def get (self , endpoint , params = None , as_json = True ):
104104 params = params or {}
0 commit comments