@@ -14,8 +14,8 @@ use parking_lot::Mutex;
1414use pyo3:: { exceptions:: PyException , prelude:: * } ;
1515
1616use super :: to_pyerr;
17- use dynamo_runtime:: CancellationToken ;
18- use dynamo_runtime :: transports :: etcd :: { Client , KvCache } ;
17+ use dynamo_runtime:: transports :: etcd :: { self , Client , KvCache } ;
18+ use tokio_util :: sync :: CancellationToken ;
1919
2020// All three AI's I asked agreed, this is the way
2121const NONE_SENTINEL : usize = usize:: MAX ;
@@ -45,32 +45,39 @@ pub struct VirtualConnectorCoordinator(Arc<InnerConnector>);
4545impl VirtualConnectorCoordinator {
4646 #[ new]
4747 pub fn new (
48- runtime : super :: DistributedRuntime ,
48+ drt : super :: DistributedRuntime ,
4949 dynamo_namespace : & str ,
5050 check_interval_secs : usize ,
5151 max_wait_time_secs : usize ,
5252 max_retries : usize ,
53- ) -> Self {
53+ ) -> PyResult < Self > {
5454 let check_interval = Duration :: from_secs ( check_interval_secs as u64 ) ;
5555 let max_wait_time = Duration :: from_secs ( max_wait_time_secs as u64 ) ;
56+ // default reads from environment variables
57+ let etcd_config = etcd:: ClientOptions :: default ( ) ;
58+ // etcd client construction is async, but async python constructors are not allowed
59+ let etcd_client = drt
60+ . inner
61+ . runtime ( )
62+ . secondary ( )
63+ . block_on (
64+ async move { etcd:: Client :: new ( etcd_config, drt. inner . runtime ( ) . clone ( ) ) . await } ,
65+ )
66+ . map_err ( to_pyerr) ?;
5667
5768 let c = InnerConnector {
5869 check_interval,
5970 max_wait_time,
6071 max_retries,
6172 namespace : dynamo_namespace. to_string ( ) ,
62- etcd_client : runtime
63- . inner ( )
64- . etcd_client ( )
65- . expect ( "Planner cannot run without etcd / in static mode" ) ,
66-
73+ etcd_client,
6774 kv_cache : Mutex :: new ( None ) ,
6875 num_prefill_workers : AtomicUsize :: new ( NONE_SENTINEL ) ,
6976 num_decode_workers : AtomicUsize :: new ( NONE_SENTINEL ) ,
7077 decision_id : AtomicUsize :: new ( NONE_SENTINEL ) ,
7178 first_skip_timestamp : AtomicUsize :: new ( NONE_SENTINEL ) ,
7279 } ;
73- Self ( Arc :: new ( c) )
80+ Ok ( Self ( Arc :: new ( c) ) )
7481 }
7582
7683 #[ pyo3( signature = ( ) ) ]
@@ -365,16 +372,24 @@ pub struct VirtualConnectorClient(Arc<InnerClient>);
365372#[ pymethods]
366373impl VirtualConnectorClient {
367374 #[ new]
368- pub fn new ( runtime : super :: DistributedRuntime , dynamo_namespace : & str ) -> Self {
375+ pub fn new ( drt : super :: DistributedRuntime , dynamo_namespace : & str ) -> PyResult < Self > {
376+ let runtime = drt. inner . runtime ( ) ;
377+ let cancellation_token = runtime. child_token ( ) ;
378+ // default reads from environment variables
379+ let etcd_config = etcd:: ClientOptions :: default ( ) ;
380+ // etcd client construction is async, but async python constructors are not allowed
381+ let etcd_client = runtime
382+ . secondary ( )
383+ . block_on (
384+ async move { etcd:: Client :: new ( etcd_config, drt. inner . runtime ( ) . clone ( ) ) . await } ,
385+ )
386+ . map_err ( to_pyerr) ?;
369387 let c = InnerClient {
370- etcd_client : runtime
371- . inner
372- . etcd_client ( )
373- . expect ( "Planner cannot run without etcd / in static mode" ) ,
388+ etcd_client,
374389 key : root_key ( dynamo_namespace) ,
375- cancellation_token : runtime . inner ( ) . child_token ( ) ,
390+ cancellation_token,
376391 } ;
377- Self ( Arc :: new ( c) )
392+ Ok ( Self ( Arc :: new ( c) ) )
378393 }
379394
380395 /// Get the current values as a PlannerDecision
0 commit comments