Error with interval speed

So my system is meant to be designed to run queries at any defined ms (millisecond). If it set it to 100ms, it runs fine (at 10/sec) and similarly at 200ms (at 5/sec). However, if I want to run at 170ms for example, it will default to 200ms. I assume this might be because it is only running on whole numbers, and so is ignoring any decimal place in the below calculation. Any help on how I can fix this?

config.Dac.RequestRateMs = 200

type DacConfig struct {
	MaxConnections int
	RequestRateMs  int // In milliseconds

	HostPort string
}

type DacClient struct {
	Connection  net.Conn
	Config      DacConfig
	RateLimiter ratelimit.Limiter
}

func NewDacClient(config Config) DacClient {
	return DacClient{
		nil,
		config.Dac,
		ratelimit.New(1000/config.Dac.RequestRateMs, ratelimit.WithoutSlack),
	}
}

That is true. Use floats:

package main

import (
	"fmt"
)

func main() {
	rate1 := 1000 / 170
	fmt.Println(rate1)

	rate2 := 1000.0 / 170.0
	fmt.Println(rate2)

}

Output:

5
5.882352941176471

see https://play.golang.org/p/Htr0fNZZWfD

Thank you, I tried that but using your example, it continued to query at 200ms. If I changed it to 150.0, it ran at 167ms!!!

config.Dac.RequestRateMs = 150.0

type DacConfig struct {
	MaxConnections int
	RequestRateMs  int // In milliseconds

	HostPort string
}

type DacClient struct {
	Connection  net.Conn
	Config      DacConfig
	RateLimiter ratelimit.Limiter
}

func NewDacClient(config Config) DacClient {
	return DacClient{
		nil,
		config.Dac,
		ratelimit.New(1000.0/config.Dac.RequestRateMs, ratelimit.WithoutSlack),
	}
}

@ianmd You’re still dividing ints. Try something like this:

ratelimit.New(int(1000.0/float32(config.Dac.RequestRateMs)), ratelimit.WithoutSlack),

EDIT: On second thought, this night not work either. How does the rate limiter work? Does it actually delay messages by the given ms or does it only allow int(1000/RequestRateMs) requests per second (i.e. if RequestRateMs = 100, could the implementation actually send 10 requests within 200ms and then sleep for 800ms)?

Tried that but didn’t work sadly, it gets me as far as sending requests between 100 and 200ms, but not exactly as defined, i.e. setting 150ms is still sending every 167ms.

The system operates by sending at regular intervals rather than all within a set time then sleep, so should send every 150ms.

What hapens if you don’t calculate the rate but write it in your code? Like this:

ratelimit.New(167, ratelimit.WithoutSlack),

Using that example, it queries at like 5ms speeds, not 167ms. If I increase 167 to 167000 (in case it is struggling to determine ms) it does the same, runs too fast!

Which library is ratelimit?

My assumption is go.uber.org/ratelimit as it matches the interface.

Its a leaky bucket…

As any ratelimit, its note meant to be used to run something every X seconds, but to make sure something is not run more often than Y times per second.

If one wants to run a command every X seconds, one should use an infinite loop in a goroutine receiving from a time.Ticker, at least thats my opinion.

1 Like

These are the associated libraries etc

import (
	"bufio"
	"fmt"
	"net"
	"strings"
	"time"

	"go.uber.org/zap"

	"go.uber.org/ratelimit"
)

Unfortunately it seems my developer used a lot of third party applications which is proving problematic at every turn.

There is nothing wrong in using 3rd party libraries. Especially with those by uber I’ve had good experiences. I really like zap for logging, and I think other libraries are battle proven as well.

Though one needs to use them correctly.

Also, 5ms when configured for 167 events per second, seems to be roughly correct and is in the range of rounding errors, especially as ratelimit.New() takes an int as first argument. Also there are probably some events with 6ms pause inbetween. Thats to adjust the tokens back to be able to meet the 167 times per second goal.

From the point of a ratelimiter, it would be even fine to do do all of those 167 requests in the first 150ms and then pause for 850ms (Though, that are the really badly implemented ones).

So if you want an interval based, close to exact rate, use a time.Ticker, as already mentioned above.

1 Like

Sorry, for clarification, I’m querying 150ms intervals, so 6.66 per second, which it cannot cope with. Seems fine with round numbers, so 100ms intervals, 200ms intervals etc.

The interface of the function takes int, int does not have a fractional part. You can have 6 events per second or 7, but not 6.66.

Let me repeat again, a rate limiter is not to specify intervals, it is to specify a maximum number of events per timeframe. Or a maximum of transferred bytes per timeframe, or a maximum of whatever per timeframe.

Nothing in the nature of a ratelimiter requires it to stretch those events over the timeframe, it could as well burst and pause, and would still it job correctly.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.