@@ -294,7 +294,14 @@ def __exit__(self, exc_type, exc_value, traceback):
294
294
self .close ()
295
295
296
296
def route (self , database ):
297
- """ Fetch a routing table from the server.
297
+ """ Fetch a routing table from the server for the given
298
+ `database`. For Bolt 4.3 and above, this appends a ROUTE
299
+ message; for earlier versions, a procedure call is made via
300
+ the regular Cypher execution mechanism. In all cases, this is
301
+ sent to the network, and a response is fetched.
302
+
303
+ :param database: database for which to fetch a routing table
304
+ :return: dictionary of raw routing data
298
305
"""
299
306
300
307
def run (self , query , parameters = None , mode = None , bookmarks = None , metadata = None ,
@@ -666,27 +673,41 @@ def create_routing_table(self, database):
666
673
if database not in self .routing_tables :
667
674
self .routing_tables [database ] = RoutingTable (database = database , routers = self .get_default_database_initial_router_addresses ())
668
675
669
- def fetch_routing_info (self , * , address , timeout , database ):
676
+ def fetch_routing_info (self , address , database , timeout ):
670
677
""" Fetch raw routing info from a given router address.
671
678
672
679
:param address: router address
673
- :param timeout: seconds
674
- :param database: the data base name to get routing table for
675
- :param address: the address by which the client initially contacted the server as a hint for inclusion in the returned routing table.
680
+ :param database: the database name to get routing table for
681
+ :param timeout: connection acquisition timeout in seconds
676
682
677
- :return: list of routing records or
678
- None if no connection could be established
679
- :raise ServiceUnavailable: if the server does not support routing or
680
- if routing support is broken
683
+ :return: list of routing records, or None if no connection
684
+ could be established or if no readers or writers are present
685
+ :raise ServiceUnavailable: if the server does not support
686
+ routing, or if routing support is broken or outdated
681
687
"""
682
688
try :
683
689
with self ._acquire (address , timeout ) as cx :
684
- return cx .route (database or self .workspace_config .database )
690
+ routing_table = cx .route (database or self .workspace_config .database )
685
691
except BoltRoutingError as error :
692
+ # Connection was successful, but routing support is
693
+ # broken. This may indicate that the routing procedure
694
+ # does not exist (for protocol versions prior to 4.3).
695
+ # This error is converted into ServiceUnavailable,
696
+ # therefore surfacing to the application as a signal that
697
+ # routing is broken.
698
+ log .debug ("Routing is broken (%s)" , error )
686
699
raise ServiceUnavailable (* error .args )
687
- except ServiceUnavailable :
688
- self .deactivate (address = address )
689
- return None
700
+ except ServiceUnavailable as error :
701
+ # The routing table request suffered a connection
702
+ # failure. This should return a null routing table,
703
+ # signalling to the caller to retry the request
704
+ # elsewhere.
705
+ log .debug ("Routing is unavailable (%s)" , error )
706
+ routing_table = None
707
+ # If the routing table is empty, deactivate the address.
708
+ if not routing_table :
709
+ self .deactivate (address )
710
+ return routing_table
690
711
691
712
def fetch_routing_table (self , * , address , timeout , database ):
692
713
""" Fetch a routing table from a given router address.
@@ -702,7 +723,7 @@ def fetch_routing_table(self, *, address, timeout, database):
702
723
:raise neo4j.exceptions.ServiceUnavailable: if no writers are available
703
724
:raise neo4j._exceptions.BoltProtocolError: if the routing information received is unusable
704
725
"""
705
- new_routing_info = self .fetch_routing_info (address = address , timeout = timeout , database = database )
726
+ new_routing_info = self .fetch_routing_info (address , database , timeout )
706
727
if new_routing_info is None :
707
728
return None
708
729
elif not new_routing_info :
0 commit comments