@@ -532,9 +532,18 @@ func (c *Cacher) Watch(ctx context.Context, key string, opts storage.ListOptions
532
532
return nil , err
533
533
}
534
534
535
- readyGeneration , err := c .ready .waitAndReadGeneration (ctx )
536
- if err != nil {
537
- return nil , errors .NewServiceUnavailable (err .Error ())
535
+ var readyGeneration int
536
+ if utilfeature .DefaultFeatureGate .Enabled (features .ResilientWatchCacheInitialization ) {
537
+ var ok bool
538
+ readyGeneration , ok = c .ready .checkAndReadGeneration ()
539
+ if ! ok {
540
+ return nil , errors .NewTooManyRequests ("storage is (re)initializing" , 1 )
541
+ }
542
+ } else {
543
+ readyGeneration , err = c .ready .waitAndReadGeneration (ctx )
544
+ if err != nil {
545
+ return nil , errors .NewServiceUnavailable (err .Error ())
546
+ }
538
547
}
539
548
540
549
// determine the namespace and name scope of the watch, first from the request, secondarily from the field selector
@@ -676,6 +685,14 @@ func (c *Cacher) Get(ctx context.Context, key string, opts storage.GetOptions, o
676
685
return c .storage .Get (ctx , key , opts , objPtr )
677
686
}
678
687
688
+ if utilfeature .DefaultFeatureGate .Enabled (features .ResilientWatchCacheInitialization ) {
689
+ if ! c .ready .check () {
690
+ // If Cache is not initialized, delegate Get requests to storage
691
+ // as described in https://kep.k8s.io/4568
692
+ return c .storage .Get (ctx , key , opts , objPtr )
693
+ }
694
+ }
695
+
679
696
// If resourceVersion is specified, serve it from cache.
680
697
// It's guaranteed that the returned value is at least that
681
698
// fresh as the given resourceVersion.
@@ -684,16 +701,18 @@ func (c *Cacher) Get(ctx context.Context, key string, opts storage.GetOptions, o
684
701
return err
685
702
}
686
703
687
- if getRV == 0 && ! c .ready .check () {
688
- // If Cacher is not yet initialized and we don't require any specific
689
- // minimal resource version, simply forward the request to storage.
690
- return c .storage .Get (ctx , key , opts , objPtr )
691
- }
692
-
693
704
// Do not create a trace - it's not for free and there are tons
694
705
// of Get requests. We can add it if it will be really needed.
695
- if err := c .ready .wait (ctx ); err != nil {
696
- return errors .NewServiceUnavailable (err .Error ())
706
+
707
+ if ! utilfeature .DefaultFeatureGate .Enabled (features .ResilientWatchCacheInitialization ) {
708
+ if getRV == 0 && ! c .ready .check () {
709
+ // If Cacher is not yet initialized and we don't require any specific
710
+ // minimal resource version, simply forward the request to storage.
711
+ return c .storage .Get (ctx , key , opts , objPtr )
712
+ }
713
+ if err := c .ready .wait (ctx ); err != nil {
714
+ return errors .NewServiceUnavailable (err .Error ())
715
+ }
697
716
}
698
717
699
718
objVal , err := conversion .EnforcePtr (objPtr )
@@ -743,6 +762,14 @@ func shouldDelegateList(opts storage.ListOptions) bool {
743
762
return consistentReadFromStorage || hasContinuation || hasLimit || unsupportedMatch
744
763
}
745
764
765
+ func shouldDelegateListOnNotReadyCache (opts storage.ListOptions ) bool {
766
+ pred := opts .Predicate
767
+ noLabelSelector := pred .Label == nil || pred .Label .Empty ()
768
+ noFieldSelector := pred .Field == nil || pred .Field .Empty ()
769
+ hasLimit := pred .Limit > 0
770
+ return noLabelSelector && noFieldSelector && hasLimit
771
+ }
772
+
746
773
func (c * Cacher ) listItems (ctx context.Context , listRV uint64 , key string , pred storage.SelectionPredicate , recursive bool ) ([]interface {}, uint64 , string , error ) {
747
774
if ! recursive {
748
775
obj , exists , readResourceVersion , err := c .watchCache .WaitUntilFreshAndGet (ctx , listRV , key )
@@ -770,10 +797,19 @@ func (c *Cacher) GetList(ctx context.Context, key string, opts storage.ListOptio
770
797
if err != nil {
771
798
return err
772
799
}
773
- if listRV == 0 && ! c .ready .check () {
774
- // If Cacher is not yet initialized and we don't require any specific
775
- // minimal resource version, simply forward the request to storage.
776
- return c .storage .GetList (ctx , key , opts , listObj )
800
+
801
+ if utilfeature .DefaultFeatureGate .Enabled (features .ResilientWatchCacheInitialization ) {
802
+ if ! c .ready .check () && shouldDelegateListOnNotReadyCache (opts ) {
803
+ // If Cacher is not initialized, delegate List requests to storage
804
+ // as described in https://kep.k8s.io/4568
805
+ return c .storage .GetList (ctx , key , opts , listObj )
806
+ }
807
+ } else {
808
+ if listRV == 0 && ! c .ready .check () {
809
+ // If Cacher is not yet initialized and we don't require any specific
810
+ // minimal resource version, simply forward the request to storage.
811
+ return c .storage .GetList (ctx , key , opts , listObj )
812
+ }
777
813
}
778
814
requestWatchProgressSupported := etcdfeature .DefaultFeatureSupportChecker .Supports (storage .RequestWatchProgress )
779
815
if resourceVersion == "" && utilfeature .DefaultFeatureGate .Enabled (features .ConsistentListFromCache ) && requestWatchProgressSupported {
@@ -788,8 +824,16 @@ func (c *Cacher) GetList(ctx context.Context, key string, opts storage.ListOptio
788
824
attribute .Stringer ("type" , c .groupResource ))
789
825
defer span .End (500 * time .Millisecond )
790
826
791
- if err := c .ready .wait (ctx ); err != nil {
792
- return errors .NewServiceUnavailable (err .Error ())
827
+ if utilfeature .DefaultFeatureGate .Enabled (features .ResilientWatchCacheInitialization ) {
828
+ if ! c .ready .check () {
829
+ // If Cacher is not initialized, reject List requests
830
+ // as described in https://kep.k8s.io/4568
831
+ return errors .NewTooManyRequests ("storage is (re)initializing" , 1 )
832
+ }
833
+ } else {
834
+ if err := c .ready .wait (ctx ); err != nil {
835
+ return errors .NewServiceUnavailable (err .Error ())
836
+ }
793
837
}
794
838
span .AddEvent ("Ready" )
795
839
0 commit comments