Worker pool implementation to limit http requests per second

1.4k Views Asked by At

I am new to Go lang and am trying to implement restrained GCP API calls. i.e. to limit the number of API calls per second my app makes, so Google won't block me.

I've been following the worker pool pattern exemplified here.

A design in a fashion similar to the linked example would be:

  • make two channels (jobs, results) of capacity the same as the total number of API calls to make
  • create a worker pool of a certain size (say 10 workers)
  • each worker goes through the jobs channel while making API calls, and storing responses into the results channel, with 1 second waiting period

My questions are:

  • am I understanding things correctly, that 10 workers each having a 1 second waiting period means my app makes approximately 10 API calls per second?
  • how do the 10 workers communicate with each other so they don't step on each other's toes, i.e. two workers don't query the same GCS path.

And of course the ultimate question: is it an overkill using worker pools?

Thank you!

1

There are 1 best solutions below

2
On

Maybe you can implement a Throttler using Sync.Mutex and time.After something like below

package main

import (
    "fmt"
    "os"
    "os/signal"
    "sync"
    "syscall"
    "time"
)

type Throttler struct {
    invocations int
    duration time.Duration
    m sync.Mutex
    max int
}

func (t *Throttler) Throttle() {
    t.m.Lock()
    defer t.m.Unlock()
    t.invocations += 1
    if t.invocations >= t.max {
        <-time.After(t.duration) // This block until the time period expires
        t.invocations = 0
    }
}

func main() {
    t := &Throttler{
        max: 2,
        duration: time.Second,
    }
    // Launch your workers passing in the throttler created above.
    for i := 0; i < 10; i++ {
        fmt.Println("starting worker")
        go Worker(t);
    }

    // This just to prevent the main from exiting.
    c := make(chan os.Signal)
    signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    <-c // This will block until you manually exists with CRl-C
}

// worker
func Worker(t *Throttler)  {
    t.Throttle()
    fmt.Println("Work done!!")
}