@@ -44,6 +44,7 @@ use std::fmt;
44
44
use std:: net:: { IpAddr , SocketAddr } ;
45
45
use std:: str:: FromStr ;
46
46
use std:: sync:: { Arc , RwLock , RwLockReadGuard } ;
47
+ use std:: time:: Duration ;
47
48
use tracing:: { debug, error, trace, warn} ;
48
49
49
50
use self :: workload:: ApplicationTunnel ;
@@ -559,6 +560,47 @@ impl DemandProxyState {
559
560
fetch ( addr)
560
561
}
561
562
563
+ // same as fetch_workload, but if the caller knows the workload is enroute already,
564
+ // will retry on cache miss for a configured amount of time - returning the workload
565
+ // when we get it, or nothing if the timeout is exceeded, whichever happens first
566
+ pub async fn wait_for_workload (
567
+ & self ,
568
+ addr : & NetworkAddress ,
569
+ deadline : Duration ,
570
+ ) -> Option < Arc < Workload > > {
571
+ debug ! ( %addr, "wait for workload" ) ;
572
+
573
+ // Take a watch listener *before* checking state (so we don't miss anything)
574
+ let mut wl_sub = self . state . read ( ) . unwrap ( ) . workloads . new_subscriber ( ) ;
575
+
576
+ debug ! ( %addr, "got sub, waiting for workload" ) ;
577
+
578
+ if let Some ( wl) = self . fetch_workload ( addr) . await {
579
+ return Some ( wl) ;
580
+ }
581
+
582
+ // We didn't find the workload we expected, so
583
+ // loop until the subscriber wakes us on new workload,
584
+ // or we hit the deadline timeout and give up
585
+ let timeout = tokio:: time:: sleep ( deadline) ;
586
+ let subscriber = wl_sub. changed ( ) ;
587
+ tokio:: pin!( timeout) ;
588
+ tokio:: pin!( subscriber) ;
589
+ loop {
590
+ tokio:: select! {
591
+ _ = & mut timeout => {
592
+ warn!( "timed out waiting for workload from xds" ) ;
593
+ break None ;
594
+ } ,
595
+ _ = & mut subscriber => {
596
+ if let Some ( wl) = self . fetch_workload( addr) . await {
597
+ break Some ( wl) ;
598
+ }
599
+ }
600
+ } ;
601
+ }
602
+ }
603
+
562
604
// only support workload
563
605
pub async fn fetch_workload ( & self , addr : & NetworkAddress ) -> Option < Arc < Workload > > {
564
606
// Wait for it on-demand, *if* needed
@@ -805,6 +847,103 @@ mod tests {
805
847
use crate :: { strng, test_helpers} ;
806
848
use test_case:: test_case;
807
849
850
+ #[ tokio:: test]
851
+ async fn test_wait_for_workload ( ) {
852
+ let mut state = ProxyState :: default ( ) ;
853
+ let delayed_wl = Arc :: new ( test_helpers:: test_default_workload ( ) ) ;
854
+ state. workloads . insert ( delayed_wl. clone ( ) , true ) ;
855
+
856
+ let mut registry = Registry :: default ( ) ;
857
+ let metrics = Arc :: new ( crate :: proxy:: Metrics :: new ( & mut registry) ) ;
858
+ let mock_proxy_state = DemandProxyState :: new (
859
+ Arc :: new ( RwLock :: new ( state) ) ,
860
+ None ,
861
+ ResolverConfig :: default ( ) ,
862
+ ResolverOpts :: default ( ) ,
863
+ metrics,
864
+ ) ;
865
+
866
+ // Some from Address
867
+ let dst = NetworkAddress {
868
+ network : strng:: EMPTY ,
869
+ address : IpAddr :: V4 ( Ipv4Addr :: LOCALHOST ) ,
870
+ } ;
871
+
872
+ test_helpers:: assert_eventually (
873
+ Duration :: from_secs ( 1 ) ,
874
+ || mock_proxy_state. wait_for_workload ( & dst, Duration :: from_millis ( 50 ) ) ,
875
+ Some ( delayed_wl) ,
876
+ )
877
+ . await ;
878
+ }
879
+
880
+ #[ tokio:: test]
881
+ async fn test_wait_for_workload_delay_fails ( ) {
882
+ let state = ProxyState :: default ( ) ;
883
+
884
+ let mut registry = Registry :: default ( ) ;
885
+ let metrics = Arc :: new ( crate :: proxy:: Metrics :: new ( & mut registry) ) ;
886
+ let mock_proxy_state = DemandProxyState :: new (
887
+ Arc :: new ( RwLock :: new ( state) ) ,
888
+ None ,
889
+ ResolverConfig :: default ( ) ,
890
+ ResolverOpts :: default ( ) ,
891
+ metrics,
892
+ ) ;
893
+
894
+ // Some from Address
895
+ let dst = NetworkAddress {
896
+ network : strng:: EMPTY ,
897
+ address : IpAddr :: V4 ( Ipv4Addr :: LOCALHOST ) ,
898
+ } ;
899
+
900
+ test_helpers:: assert_eventually (
901
+ Duration :: from_millis ( 10 ) ,
902
+ || mock_proxy_state. wait_for_workload ( & dst, Duration :: from_millis ( 5 ) ) ,
903
+ None ,
904
+ )
905
+ . await ;
906
+ }
907
+
908
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
909
+ async fn test_wait_for_workload_eventually ( ) {
910
+ let state = ProxyState :: default ( ) ;
911
+ let wrap_state = Arc :: new ( RwLock :: new ( state) ) ;
912
+ let delayed_wl = Arc :: new ( test_helpers:: test_default_workload ( ) ) ;
913
+
914
+ let mut registry = Registry :: default ( ) ;
915
+ let metrics = Arc :: new ( crate :: proxy:: Metrics :: new ( & mut registry) ) ;
916
+ let mock_proxy_state = DemandProxyState :: new (
917
+ wrap_state. clone ( ) ,
918
+ None ,
919
+ ResolverConfig :: default ( ) ,
920
+ ResolverOpts :: default ( ) ,
921
+ metrics,
922
+ ) ;
923
+
924
+ // Some from Address
925
+ let dst = NetworkAddress {
926
+ network : strng:: EMPTY ,
927
+ address : IpAddr :: V4 ( Ipv4Addr :: LOCALHOST ) ,
928
+ } ;
929
+
930
+ let expected_wl = delayed_wl. clone ( ) ;
931
+ let t = tokio:: spawn ( async move {
932
+ test_helpers:: assert_eventually (
933
+ Duration :: from_millis ( 500 ) ,
934
+ || mock_proxy_state. wait_for_workload ( & dst, Duration :: from_millis ( 250 ) ) ,
935
+ Some ( expected_wl) ,
936
+ )
937
+ . await ;
938
+ } ) ;
939
+ wrap_state
940
+ . write ( )
941
+ . unwrap ( )
942
+ . workloads
943
+ . insert ( delayed_wl, true ) ;
944
+ t. await . expect ( "should not fail" ) ;
945
+ }
946
+
808
947
#[ tokio:: test]
809
948
async fn lookup_address ( ) {
810
949
let mut state = ProxyState :: default ( ) ;
0 commit comments