[hotfix] CLI arg to specify average duration per event threshold for loadtest to succeed (#2300)

* CLI arg to specify average duration per event threshold for loadtest to succeed

* add tolerance

* fix failing load go test
This commit is contained in:
Mohammed Nafees
2025-09-16 18:52:38 +02:00
committed by GitHub
parent c1ebeb518a
commit 193b6ed803
3 changed files with 114 additions and 95 deletions

View File

@@ -13,7 +13,7 @@ type avgResult struct {
}
func do(config LoadTestConfig) error {
l.Info().Msgf("testing with duration=%s, eventsPerSecond=%d, delay=%s, wait=%s, concurrency=%d", config.Duration, config.Events, config.Delay, config.Wait, config.Concurrency)
l.Info().Msgf("testing with duration=%s, eventsPerSecond=%d, delay=%s, wait=%s, concurrency=%d, averageDurationThreshold=%s", config.Duration, config.Events, config.Delay, config.Wait, config.Concurrency, config.AverageDurationThreshold)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -115,6 +115,17 @@ func do(config LoadTestConfig) error {
return fmt.Errorf("❌ emitted and unique executed counts do not match: %d != %d", int64(config.EventFanout)*emitted, uniques)
}
// Add a small tolerance (1% or 1ms, whichever is smaller)
tolerance := config.AverageDurationThreshold / 100 // 1% tolerance
if tolerance > time.Millisecond {
tolerance = time.Millisecond
}
thresholdWithTolerance := config.AverageDurationThreshold + tolerance
if finalDurationResult.avg > thresholdWithTolerance {
return fmt.Errorf("❌ average duration per executed event is greater than the threshold (with tolerance): %s > %s (threshold: %s, tolerance: %s)", finalDurationResult.avg, thresholdWithTolerance, config.AverageDurationThreshold, tolerance)
}
log.Printf("✅ success")
return nil

View File

@@ -36,110 +36,116 @@ func TestLoadCLI(t *testing.T) {
{
name: "test simple workflow",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
AverageDurationThreshold: 200 * time.Millisecond,
},
},
{
name: "test with DAG",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 2,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 2,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
AverageDurationThreshold: 200 * time.Millisecond,
},
},
{
name: "test with event fanout",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 2,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 2,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
AverageDurationThreshold: 200 * time.Millisecond,
},
},
{
name: "test with global concurrency key",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 10,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 10,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
AverageDurationThreshold: 200 * time.Millisecond,
},
},
{
name: "test for many queued events and little worker throughput",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
WorkerDelay: 120 * time.Second, // will write 1200 events before the worker is ready
Wait: 120 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
WorkerDelay: 120 * time.Second, // will write 1200 events before the worker is ready
Wait: 120 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
AverageDurationThreshold: 200 * time.Millisecond,
},
},
{
name: "test with rate limits",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 10,
RlLimit: 100,
RlDurationUnit: "second",
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 10,
RlLimit: 100,
RlDurationUnit: "second",
AverageDurationThreshold: 200 * time.Millisecond,
},
},
}

View File

@@ -19,21 +19,22 @@ var l zerolog.Logger
// LoadTestConfig holds all configuration for the load test
type LoadTestConfig struct {
Namespace string
Events int
Concurrency int
Duration time.Duration
Wait time.Duration
Delay time.Duration
WorkerDelay time.Duration
Slots int
FailureRate float32
PayloadSize string
EventFanout int
DagSteps int
RlKeys int
RlLimit int
RlDurationUnit string
Namespace string
Events int
Concurrency int
Duration time.Duration
Wait time.Duration
Delay time.Duration
WorkerDelay time.Duration
Slots int
FailureRate float32
PayloadSize string
EventFanout int
DagSteps int
RlKeys int
RlLimit int
RlDurationUnit string
AverageDurationThreshold time.Duration
}
func main() {
@@ -81,6 +82,7 @@ func main() {
loadtest.Flags().IntVar(&config.RlLimit, "rlLimit", 0, "rlLimit specifies the rate limit")
loadtest.Flags().StringVar(&config.RlDurationUnit, "rlDurationUnit", "second", "rlDurationUnit specifies the duration unit for the rate limit (second, minute, hour)")
loadtest.Flags().StringVarP(&logLevel, "level", "l", "info", "logLevel specifies the log level (debug, info, warn, error)")
loadtest.Flags().DurationVar(&config.AverageDurationThreshold, "averageDurationThreshold", 100*time.Millisecond, "averageDurationThreshold specifies the threshold for the average duration per executed event to be considered a success")
cmd := &cobra.Command{Use: "app"}
cmd.AddCommand(loadtest)