3939from ravendb .http .raven_command import RavenCommand , RavenCommandResponseType
4040from ravendb .http .server_node import ServerNode
4141from ravendb .http .topology import Topology , NodeStatus , NodeSelector , CurrentIndexAndNode , UpdateTopologyParameters
42+ from ravendb .http import topology_local_cache
4243from ravendb .serverwide .commands import GetDatabaseTopologyCommand , GetClusterTopologyCommand
4344
4445from http import HTTPStatus
@@ -416,6 +417,14 @@ def __supply_async():
416417
417418 self ._topology_etag = self ._node_selector .topology .etag
418419
420+ if not self .conventions .disable_topology_cache and self .conventions .topology_cache_location :
421+ topology_local_cache .try_save (
422+ self .conventions .topology_cache_location ,
423+ topology_local_cache .server_hash (parameters .node .url , self ._database_name ),
424+ self ._node_selector .topology ,
425+ topology_local_cache .DATABASE_TOPOLOGY_EXTENSION ,
426+ )
427+
419428 self ._on_topology_updated_invoke (topology )
420429 except Exception as e :
421430 if not self ._disposed :
@@ -456,6 +465,16 @@ def __run(errors: list):
456465
457466 errors .append ((url , e ))
458467
468+ # all initial urls unreachable - fall back to the on-disk topology cache when enabled
469+ for url in initial_urls :
470+ cached_topology = self ._try_load_topology_from_cache (url )
471+ if cached_topology is not None :
472+ self ._node_selector = NodeSelector (cached_topology , self ._thread_pool_executor )
473+ self ._topology_etag = cached_topology .etag
474+ self .__initialize_update_topology_timer ()
475+ self .__topology_taken_from_node = ServerNode (url , self ._database_name )
476+ return
477+
459478 topology = Topology (
460479 self ._topology_etag ,
461480 (
@@ -476,6 +495,13 @@ def __run(errors: list):
476495
477496 return self ._thread_pool_executor .submit (__run , errors )
478497
498+ def _try_load_topology_from_cache (self , url ):
499+ return topology_local_cache .try_load (
500+ None if self .conventions .disable_topology_cache else self .conventions .topology_cache_location ,
501+ topology_local_cache .server_hash (url , self ._database_name ),
502+ topology_local_cache .DATABASE_TOPOLOGY_EXTENSION ,
503+ )
504+
479505 @staticmethod
480506 def validate_urls (initial_urls : List [str ]) -> List [str ]:
481507 # todo: implement validation
@@ -635,7 +661,7 @@ def execute(
635661 return # we either handled this already in the unsuccessful response or we are throwing
636662 self ._on_succeed_request_invoke (self ._database_name , url , response , request , attempt_num )
637663 response_dispose = command .process_response (self ._cache , response , url )
638- self ._last_returned_response = datetime .datetime .utcnow ( )
664+ self ._last_returned_response = datetime .datetime .now ( datetime . timezone . utc ). replace ( tzinfo = None )
639665 finally :
640666 if response_dispose == ResponseDisposeHandling .AUTOMATIC :
641667 response .close ()
@@ -1445,6 +1471,14 @@ def __supply_async():
14451471 new_topology = Topology (results .etag , nodes )
14461472 self ._topology_etag = results .etag
14471473
1474+ if not self .conventions .disable_topology_cache and self .conventions .topology_cache_location :
1475+ topology_local_cache .try_save (
1476+ self .conventions .topology_cache_location ,
1477+ topology_local_cache .server_hash (parameters .node .url ),
1478+ new_topology ,
1479+ topology_local_cache .CLUSTER_TOPOLOGY_EXTENSION ,
1480+ )
1481+
14481482 if self ._node_selector is None :
14491483 self ._node_selector = NodeSelector (new_topology , self ._thread_pool_executor )
14501484
@@ -1469,5 +1503,12 @@ def __supply_async():
14691503
14701504 return self ._thread_pool_executor .submit (__supply_async )
14711505
1506+ def _try_load_topology_from_cache (self , url ):
1507+ return topology_local_cache .try_load (
1508+ None if self .conventions .disable_topology_cache else self .conventions .topology_cache_location ,
1509+ topology_local_cache .server_hash (url ),
1510+ topology_local_cache .CLUSTER_TOPOLOGY_EXTENSION ,
1511+ )
1512+
14721513 def _throw_exceptions (self , details : str ):
14731514 raise RuntimeError (f"Failed to retrieve cluster topology from all known nodes { os .linesep } { details } " )
0 commit comments