Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rate.Limiter to RunConfiguration #65

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

aromanovich
Copy link
Contributor

What was changed

RunConfiguration now accepts *rate.Limiter.

Why?

To allow spreading out the load surge caused by going from 0 to MaxConcurrent runs in the beginning of the benchmark.

Checklist

  1. No issues to close.

  2. How was this tested:
    I ran benchmarks.

  3. Any docs updates needed?
    No.

@@ -25,6 +26,7 @@ type genericRun struct {
info ScenarioInfo
config RunConfiguration
logger *zap.SugaredLogger
limiter *rate.Limiter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this repeated here when it's stored on config? In fact, it seems this field is read but never written - I'm not sure anything's actually happening yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦 You're totally right. This is a leftover from my initial draft hardcoded implementation.

I've fixed it, now the construction like this works as expected:

loadgen.MustRegisterScenario(loadgen.Scenario{
	Description: "Each iteration executes a single workflow with a noop activity.",
	Executor: loadgen.KitchenSinkExecutor{
		DefaultConfiguration: loadgen.RunConfiguration{
			Limiter: rate.NewLimiter(rate.Every(time.Second * 5), 1),
		},
		TestInput: &kitchensink.TestInput{
			WorkflowInput: &kitchensink.WorkflowInput{
				InitialActions: []*kitchensink.ActionSet{
					kitchensink.NoOpSingleActivityActionSet(),
				},
			},
		},
	},
})

Copy link
Member

@cretz cretz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aromanovich - be advised, if you're using this as a library, the API will never be considered stable and may change in backwards incompatible ways regularly. Even the CLI may not be completely stable, but definitely more so than the API. If possible, you should consider exposing whatever advanced limiting options you need from the CLI.

Comment on lines +110 to +119
var runStartTime time.Time
err := func() error {
if g.config.Limiter != nil {
if innerErr := g.config.Limiter.Wait(ctx); innerErr != nil {
return innerErr
}
}
runStartTime = time.Now()
return g.executor.Execute(ctx, run)
}()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var runStartTime time.Time
err := func() error {
if g.config.Limiter != nil {
if innerErr := g.config.Limiter.Wait(ctx); innerErr != nil {
return innerErr
}
}
runStartTime = time.Now()
return g.executor.Execute(ctx, run)
}()
runStartTime := time.Now()
var err error
if g.config.Limiter != nil {
err = g.config.Limiter.Wait(ctx)
}
if err == nil {
err = g.executor.Execute(ctx, run)
}

Doesn't seem to be much benefit in the inner function. I don't think we have to overly worry about err reuse.

err := g.executor.Execute(ctx, run)
var runStartTime time.Time
err := func() error {
if g.config.Limiter != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be worked into the part above this goroutine where we do waiting? Seeing max-concurrent, we have traditionally waited in the synchronous loop before instantiating the run.

@@ -119,6 +123,8 @@ type RunConfiguration struct {
// Maximum number of instances of the Execute method to run concurrently.
// Default is DefaultMaxConcurrent.
MaxConcurrent int
// Rate limiter to be Wait-ed before each iteration.
Limiter *rate.Limiter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Limiter *rate.Limiter
Limiter interface { Wait(context.Context) error }

Quite a bit more flexible

Comment on lines +137 to +139
if r.Limiter == nil {
r.Limiter = DefaultRateLimiter
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if r.Limiter == nil {
r.Limiter = DefaultRateLimiter
}

Seems a nil rate limiter is supported at runtime

Comment on lines +57 to +59
if run.config.Limiter == nil {
run.config.Limiter = g.DefaultConfiguration.Limiter
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if run.config.Limiter == nil {
run.config.Limiter = g.DefaultConfiguration.Limiter
}

Seems a nil limiter is supported at runtime

Comment on lines +114 to +116
// DefaultRateLimiter is unlimited
var DefaultRateLimiter = rate.NewLimiter(rate.Inf, 0)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// DefaultRateLimiter is unlimited
var DefaultRateLimiter = rate.NewLimiter(rate.Inf, 0)

Seems a nil limiter is supported at runtime

Copy link
Member

@cretz cretz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(sorry, removing accidental approval from earlier)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants