Full Blog TOC

Full Blog Table Of Content with Keywords Available HERE

Tuesday, April 13, 2021

Throttle API calls in GO


 


In this post we will review how to throttle API calls to a library in GO.

We assume that the library does some updates upon a notification. In this case, the notification does not contain any data, it simply means: "Something changed, do your stuff". 

Now, we want the update to occur no more than once in a minute. It does not matter how many time it was notified, only that the library does its work no more than once in a minute.

To do this, we use an updates channel, and a GO routine. The throttle struct includes the channel for updates, as well as the configuration of throttle.



package throttle

import (
"time"
)

type Handler func() error

type Throttle struct {
interval time.Duration
handler Handler
updates chan bool
lastRun time.Time
}

func CreateThrottle(
interval time.Duration,
handler Handler,
) *Throttle {
return &Throttle{
interval: interval,
handler: handler,
updates: make(chan bool, 100),
lastRun: time.Now(),
}
}




Next we include the API calls for the throttle:



func (t *Throttle) Start() {
go t.channelLoop()
}

func (t *Throttle) Notify() {
t.updates <- true
}



and last, we implement the GO routine to handle the updates. Notice that in case the notifications are too frequent, we schedule a later run of the API upon a timer.



func (t *Throttle) channelLoop() {
var nextTimeout *time.Duration

for {
if nextTimeout == nil {
_ = <-t.updates
} else {
select {
case _ = <-t.updates:
case <-time.After(*nextTimeout):
}
}

passedTime := time.Now().Sub(t.lastRun)
if passedTime < t.interval {
timeout := t.interval - passedTime
nextTimeout = &timeout
} else {
err := t.handler()
if err != nil {
panic(err)
}
t.lastRun = time.Now()
nextTimeout = nil
}
}
}



That's it! 

The throttle API is ready. Let's see and example of usage:



throttling = CreateThrottle(time.Minute, myExecutor)
throttling.Start()












No comments:

Post a Comment