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 }