4

Just started learning about the power of goroutines.

I have ~100 accounts and ~10 regions, looping through them to create ~ 1000 goroutines with golang to increase the reading speed. It worked too fast that it hit the API return limit of 20/ sec.

How do I ensure that all the goroutines can maintain at the maximum call rate of (20/s)? Im unsure of which golang concurrency methods works best together to handle the error.

eg:

func readInstance(acc string, region string, wg *sync.WaitGroup) {
    defer wg.Done()
    response, err := client.DescribeInstances(acc, region)
    if err != nil {
        log.Println(err) // API limit exceeding 20
        return
    }
    .
    .
    .
    .

}

func main() {
    accounts := []string{"g", "h", "i", ...}
    regions := []string{"g", "h", "i", ...}
    for _, region := range regions {
        for i := 0; i < len(accounts); i++ {
            wg.Add(1)
            go readInstance(accounts[i], region, &wg)
        }
    }
    wg.Wait()
}

2 Answers2

3

If you have a fixed upper limit on how many requests you can do in a particular amount of real time, you can use a time.NewTicker() to space things out.

c := time.NewTicker(50 * time.Millisecond)
defer c.Stop()

Now, when you want to make a server request, just insert

<- c.C

prior to the actual request.

Tinkerer
  • 865
  • 7
  • 9
  • Thanks! Created a global ticker and pass as a pointer into all the goroutines works! –  Oct 11 '21 at 07:28
  • 1
    Coles, for a small improvement to how you can pass channels see https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function – Kangur Oct 11 '21 at 09:50
0

i think you can try this: https://github.com/uber-go/ratelimit

According to the documentation, it is concurrency safe.

import (
    "fmt"
    "time"

    "go.uber.org/ratelimit"
)

func main() {
    rl := ratelimit.New(100) // per second

    prev := time.Now()
    for i := 0; i < 10; i++ {
        now := rl.Take()
        fmt.Println(i, now.Sub(prev))
        prev = now
    }

    // Output:
    // 0 0
    // 1 10ms
    // 2 10ms
    // 3 10ms
    // 4 10ms
    // 5 10ms
    // 6 10ms
    // 7 10ms
    // 8 10ms
    // 9 10ms
}