github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/k8s.io/kubernetes/pkg/util/wait/wait.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors All rights reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package wait
    18  
    19  import (
    20  	"errors"
    21  	"math/rand"
    22  	"time"
    23  
    24  	"k8s.io/kubernetes/pkg/util/runtime"
    25  )
    26  
    27  // For any test of the style:
    28  //   ...
    29  //   <- time.After(timeout):
    30  //      t.Errorf("Timed out")
    31  // The value for timeout should effectively be "forever." Obviously we don't want our tests to truly lock up forever, but 30s
    32  // is long enough that it is effectively forever for the things that can slow down a run on a heavily contended machine
    33  // (GC, seeks, etc), but not so long as to make a developer ctrl-c a test run if they do happen to break that test.
    34  var ForeverTestTimeout = time.Second * 30
    35  
    36  // NeverStop may be passed to Until to make it never stop.
    37  var NeverStop <-chan struct{} = make(chan struct{})
    38  
    39  // Forever is syntactic sugar on top of Until
    40  func Forever(f func(), period time.Duration) {
    41  	Until(f, period, NeverStop)
    42  }
    43  
    44  // Until loops until stop channel is closed, running f every period.
    45  // Until is syntactic sugar on top of JitterUntil with zero jitter factor
    46  func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
    47  	JitterUntil(f, period, 0.0, stopCh)
    48  }
    49  
    50  // JitterUntil loops until stop channel is closed, running f every period.
    51  // If jitterFactor is positive, the period is jittered before every run of f.
    52  // If jitterFactor is not positive, the period is unchanged.
    53  // Catches any panics, and keeps going. f may not be invoked if
    54  // stop channel is already closed. Pass NeverStop to Until if you
    55  // don't want it stop.
    56  func JitterUntil(f func(), period time.Duration, jitterFactor float64, stopCh <-chan struct{}) {
    57  	select {
    58  	case <-stopCh:
    59  		return
    60  	default:
    61  	}
    62  
    63  	for {
    64  		func() {
    65  			defer runtime.HandleCrash()
    66  			f()
    67  		}()
    68  
    69  		jitteredPeriod := period
    70  		if jitterFactor > 0.0 {
    71  			jitteredPeriod = Jitter(period, jitterFactor)
    72  		}
    73  
    74  		select {
    75  		case <-stopCh:
    76  			return
    77  		case <-time.After(jitteredPeriod):
    78  		}
    79  	}
    80  }
    81  
    82  // Jitter returns a time.Duration between duration and duration + maxFactor * duration,
    83  // to allow clients to avoid converging on periodic behavior.  If maxFactor is 0.0, a
    84  // suggested default value will be chosen.
    85  func Jitter(duration time.Duration, maxFactor float64) time.Duration {
    86  	if maxFactor <= 0.0 {
    87  		maxFactor = 1.0
    88  	}
    89  	wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration))
    90  	return wait
    91  }
    92  
    93  // ErrWaitTimeout is returned when the condition exited without success
    94  var ErrWaitTimeout = errors.New("timed out waiting for the condition")
    95  
    96  // ConditionFunc returns true if the condition is satisfied, or an error
    97  // if the loop should be aborted.
    98  type ConditionFunc func() (done bool, err error)
    99  
   100  // Backoff is parameters applied to a Backoff function.
   101  type Backoff struct {
   102  	Duration time.Duration
   103  	Factor   float64
   104  	Jitter   float64
   105  	Steps    int
   106  }
   107  
   108  // ExponentialBackoff repeats a condition check up to steps times, increasing the wait
   109  // by multipling the previous duration by factor. If jitter is greater than zero,
   110  // a random amount of each duration is added (between duration and duration*(1+jitter)).
   111  // If the condition never returns true, ErrWaitTimeout is returned. All other errors
   112  // terminate immediately.
   113  func ExponentialBackoff(backoff Backoff, condition ConditionFunc) error {
   114  	duration := backoff.Duration
   115  	for i := 0; i < backoff.Steps; i++ {
   116  		if i != 0 {
   117  			adjusted := duration
   118  			if backoff.Jitter > 0.0 {
   119  				adjusted = Jitter(duration, backoff.Jitter)
   120  			}
   121  			time.Sleep(adjusted)
   122  			duration = time.Duration(float64(duration) * backoff.Factor)
   123  		}
   124  		if ok, err := condition(); err != nil || ok {
   125  			return err
   126  		}
   127  	}
   128  	return ErrWaitTimeout
   129  }
   130  
   131  // Poll tries a condition func until it returns true, an error, or the timeout
   132  // is reached. condition will always be invoked at least once but some intervals
   133  // may be missed if the condition takes too long or the time window is too short.
   134  // If you want to Poll something forever, see PollInfinite.
   135  // Poll always waits the interval before the first check of the condition.
   136  func Poll(interval, timeout time.Duration, condition ConditionFunc) error {
   137  	return pollInternal(poller(interval, timeout), condition)
   138  }
   139  
   140  func pollInternal(wait WaitFunc, condition ConditionFunc) error {
   141  	done := make(chan struct{})
   142  	defer close(done)
   143  	return WaitFor(wait, condition, done)
   144  }
   145  
   146  // PollImmediate is identical to Poll, except that it performs the first check
   147  // immediately, not waiting interval beforehand.
   148  func PollImmediate(interval, timeout time.Duration, condition ConditionFunc) error {
   149  	return pollImmediateInternal(poller(interval, timeout), condition)
   150  }
   151  
   152  func pollImmediateInternal(wait WaitFunc, condition ConditionFunc) error {
   153  	done, err := condition()
   154  	if err != nil {
   155  		return err
   156  	}
   157  	if done {
   158  		return nil
   159  	}
   160  	return pollInternal(wait, condition)
   161  }
   162  
   163  // PollInfinite polls forever.
   164  func PollInfinite(interval time.Duration, condition ConditionFunc) error {
   165  	done := make(chan struct{})
   166  	defer close(done)
   167  	return WaitFor(poller(interval, 0), condition, done)
   168  }
   169  
   170  // WaitFunc creates a channel that receives an item every time a test
   171  // should be executed and is closed when the last test should be invoked.
   172  type WaitFunc func(done <-chan struct{}) <-chan struct{}
   173  
   174  // WaitFor gets a channel from wait(), and then invokes fn once for every value
   175  // placed on the channel and once more when the channel is closed.  If fn
   176  // returns an error the loop ends and that error is returned, and if fn returns
   177  // true the loop ends and nil is returned. ErrWaitTimeout will be returned if
   178  // the channel is closed without fn ever returning true.
   179  func WaitFor(wait WaitFunc, fn ConditionFunc, done <-chan struct{}) error {
   180  	c := wait(done)
   181  	for {
   182  		_, open := <-c
   183  		ok, err := fn()
   184  		if err != nil {
   185  			return err
   186  		}
   187  		if ok {
   188  			return nil
   189  		}
   190  		if !open {
   191  			break
   192  		}
   193  	}
   194  	return ErrWaitTimeout
   195  }
   196  
   197  // poller returns a WaitFunc that will send to the channel every
   198  // interval until timeout has elapsed and then close the channel.
   199  // Over very short intervals you may receive no ticks before
   200  // the channel is closed.  If timeout is 0, the channel
   201  // will never be closed.
   202  func poller(interval, timeout time.Duration) WaitFunc {
   203  	return WaitFunc(func(done <-chan struct{}) <-chan struct{} {
   204  		ch := make(chan struct{})
   205  
   206  		go func() {
   207  			defer close(ch)
   208  
   209  			tick := time.NewTicker(interval)
   210  			defer tick.Stop()
   211  
   212  			var after <-chan time.Time
   213  			if timeout != 0 {
   214  				// time.After is more convenient, but it
   215  				// potentially leaves timers around much longer
   216  				// than necessary if we exit early.
   217  				timer := time.NewTimer(timeout)
   218  				after = timer.C
   219  				defer timer.Stop()
   220  			}
   221  
   222  			for {
   223  				select {
   224  				case <-tick.C:
   225  					// If the consumer isn't ready for this signal drop it and
   226  					// check the other channels.
   227  					select {
   228  					case ch <- struct{}{}:
   229  					default:
   230  					}
   231  				case <-after:
   232  					return
   233  				case <-done:
   234  					return
   235  				}
   236  			}
   237  		}()
   238  
   239  		return ch
   240  	})
   241  }