github.com/timstclair/heapster@v0.20.0-alpha1/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  
    25  // Jitter returns a time.Duration between duration and duration + maxFactor * duration,
    26  // to allow clients to avoid converging on periodic behavior.  If maxFactor is 0.0, a
    27  // suggested default value will be chosen.
    28  func Jitter(duration time.Duration, maxFactor float64) time.Duration {
    29  	if maxFactor <= 0.0 {
    30  		maxFactor = 1.0
    31  	}
    32  	wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration))
    33  	return wait
    34  }
    35  
    36  // ErrWaitTimeout is returned when the condition exited without success
    37  var ErrWaitTimeout = errors.New("timed out waiting for the condition")
    38  
    39  // ConditionFunc returns true if the condition is satisfied, or an error
    40  // if the loop should be aborted.
    41  type ConditionFunc func() (done bool, err error)
    42  
    43  // Poll tries a condition func until it returns true, an error, or the timeout
    44  // is reached. condition will always be invoked at least once but some intervals
    45  // may be missed if the condition takes too long or the time window is too short.
    46  // If you want to Poll something forever, see PollInfinite.
    47  // Poll always waits the interval before the first check of the condition.
    48  func Poll(interval, timeout time.Duration, condition ConditionFunc) error {
    49  	return pollInternal(poller(interval, timeout), condition)
    50  }
    51  
    52  func pollInternal(wait WaitFunc, condition ConditionFunc) error {
    53  	done := make(chan struct{})
    54  	defer close(done)
    55  	return WaitFor(wait, condition, done)
    56  }
    57  
    58  func PollImmediate(interval, timeout time.Duration, condition ConditionFunc) error {
    59  	return pollImmediateInternal(poller(interval, timeout), condition)
    60  }
    61  
    62  func pollImmediateInternal(wait WaitFunc, condition ConditionFunc) error {
    63  	done, err := condition()
    64  	if err != nil {
    65  		return err
    66  	}
    67  	if done {
    68  		return nil
    69  	}
    70  	return pollInternal(wait, condition)
    71  }
    72  
    73  // PollInfinite polls forever.
    74  func PollInfinite(interval time.Duration, condition ConditionFunc) error {
    75  	done := make(chan struct{})
    76  	defer close(done)
    77  	return WaitFor(poller(interval, 0), condition, done)
    78  }
    79  
    80  // WaitFunc creates a channel that receives an item every time a test
    81  // should be executed and is closed when the last test should be invoked.
    82  type WaitFunc func(done <-chan struct{}) <-chan struct{}
    83  
    84  // WaitFor gets a channel from wait(), and then invokes fn once for every value
    85  // placed on the channel and once more when the channel is closed.  If fn
    86  // returns an error the loop ends and that error is returned, and if fn returns
    87  // true the loop ends and nil is returned. ErrWaitTimeout will be returned if
    88  // the channel is closed without fn ever returning true.
    89  func WaitFor(wait WaitFunc, fn ConditionFunc, done <-chan struct{}) error {
    90  	c := wait(done)
    91  	for {
    92  		_, open := <-c
    93  		ok, err := fn()
    94  		if err != nil {
    95  			return err
    96  		}
    97  		if ok {
    98  			return nil
    99  		}
   100  		if !open {
   101  			break
   102  		}
   103  	}
   104  	return ErrWaitTimeout
   105  }
   106  
   107  // poller returns a WaitFunc that will send to the channel every
   108  // interval until timeout has elapsed and then close the channel.
   109  // Over very short intervals you may receive no ticks before
   110  // the channel is closed.  If timeout is 0, the channel
   111  // will never be closed.
   112  func poller(interval, timeout time.Duration) WaitFunc {
   113  	return WaitFunc(func(done <-chan struct{}) <-chan struct{} {
   114  		ch := make(chan struct{})
   115  
   116  		go func() {
   117  			defer close(ch)
   118  
   119  			tick := time.NewTicker(interval)
   120  			defer tick.Stop()
   121  
   122  			var after <-chan time.Time
   123  			if timeout != 0 {
   124  				// time.After is more convenient, but it
   125  				// potentially leaves timers around much longer
   126  				// than necessary if we exit early.
   127  				timer := time.NewTimer(timeout)
   128  				after = timer.C
   129  				defer timer.Stop()
   130  			}
   131  
   132  			for {
   133  				select {
   134  				case <-tick.C:
   135  					// If the consumer isn't ready for this signal drop it and
   136  					// check the other channels.
   137  					select {
   138  					case ch <- struct{}{}:
   139  					default:
   140  					}
   141  				case <-after:
   142  					return
   143  				case <-done:
   144  					return
   145  				}
   146  			}
   147  		}()
   148  
   149  		return ch
   150  	})
   151  }