60 lines
		
	
	
		
			925 B
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			60 lines
		
	
	
		
			925 B
		
	
	
	
		
			Go
		
	
	
	
| package limiter
 | |
| 
 | |
| import (
 | |
| 	"sync"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| // NewRateLimiter returns a rate limiter that will will emit from the C
 | |
| // channel only 'n' times every 'rate' seconds.
 | |
| func NewRateLimiter(n int, rate time.Duration) *rateLimiter {
 | |
| 	r := &rateLimiter{
 | |
| 		C:        make(chan bool),
 | |
| 		rate:     rate,
 | |
| 		n:        n,
 | |
| 		shutdown: make(chan bool),
 | |
| 	}
 | |
| 	r.wg.Add(1)
 | |
| 	go r.limiter()
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| type rateLimiter struct {
 | |
| 	C    chan bool
 | |
| 	rate time.Duration
 | |
| 	n    int
 | |
| 
 | |
| 	shutdown chan bool
 | |
| 	wg       sync.WaitGroup
 | |
| }
 | |
| 
 | |
| func (r *rateLimiter) Stop() {
 | |
| 	close(r.shutdown)
 | |
| 	r.wg.Wait()
 | |
| 	close(r.C)
 | |
| }
 | |
| 
 | |
| func (r *rateLimiter) limiter() {
 | |
| 	defer r.wg.Done()
 | |
| 	ticker := time.NewTicker(r.rate)
 | |
| 	defer ticker.Stop()
 | |
| 	counter := 0
 | |
| 	for {
 | |
| 		select {
 | |
| 		case <-r.shutdown:
 | |
| 			return
 | |
| 		case <-ticker.C:
 | |
| 			counter = 0
 | |
| 		default:
 | |
| 			if counter < r.n {
 | |
| 				select {
 | |
| 				case r.C <- true:
 | |
| 					counter++
 | |
| 				case <-r.shutdown:
 | |
| 					return
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |