decred.org/dcrdex@v1.0.5/dex/meter/meterer.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package meter 5 6 import ( 7 "context" 8 "time" 9 ) 10 11 // DelayedRelay creates a simple error signal pipeline that delays and 12 // aggregates the relaying of nil errors. Non-nil errors received on the in 13 // channel are immediately sent on the out channel without delay. If a nil error 14 // arrives within minDelay of the previous one, it will be scheduled for later 15 // to respect the configured delay. If multiple arrive within minDelay, they 16 // will be grouped into a single delayed signal. 17 func DelayedRelay(ctx context.Context, minDelay time.Duration, n int) (out <-chan error, in chan<- error) { 18 inC := make(chan error, n) 19 outC := make(chan error, n) 20 21 go func() { 22 defer close(outC) // signal shutdown to the consumer 23 24 var last time.Time 25 var scheduled *time.Timer 26 now := make(chan struct{}) 27 28 for { 29 select { 30 case err := <-inC: 31 if err != nil { 32 outC <- err 33 continue 34 } 35 36 if scheduled != nil { 37 continue 38 } 39 40 if time.Since(last) > minDelay { 41 outC <- nil 42 last = time.Now() 43 continue 44 } 45 46 delay := time.Until(last.Add(minDelay)) 47 scheduled = time.AfterFunc(delay, func() { 48 now <- struct{}{} 49 }) 50 51 case <-now: 52 outC <- nil 53 scheduled = nil 54 last = time.Now() 55 56 case <-ctx.Done(): 57 if scheduled != nil { 58 scheduled.Stop() 59 } 60 return 61 } 62 } 63 }() 64 65 return outC, inC 66 }