Files
hatchet/cmd/hatchet-loadtest/do.go
abelanger5 5c5c1aa5a1 feat: more features in the load testing harness (#1691)
* fix: make stripped payload size configurable

* feat: more load test features

* Update cmd/hatchet-loadtest/do.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: try to fix load tests

* increase timeout, update goleak ignores

* fix: data race in scheduler with snapshot input

* fix: logger improvements

* add one more goleak ignore

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-07 21:39:30 -04:00

122 lines
3.2 KiB
Go
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"fmt"
"log"
"time"
)
type avgResult struct {
count int64
avg time.Duration
}
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)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
after := 10 * time.Second
go func() {
time.Sleep(config.Duration + after + config.Wait + 5*time.Second)
cancel()
}()
ch := make(chan int64, 2)
durations := make(chan time.Duration, config.Events)
// Compute running average for executed durations using a rolling average.
durationsResult := make(chan avgResult)
go func() {
var count int64
var avg time.Duration
for d := range durations {
count++
if count == 1 {
avg = d
} else {
avg += (d - avg) / time.Duration(count)
}
}
durationsResult <- avgResult{count: count, avg: avg}
}()
// Start worker and ensure it has time to register
workerStarted := make(chan struct{})
go func() {
if config.WorkerDelay > 0 {
// run a worker to register the workflow
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
run(ctx, config, durations)
cancel()
l.Info().Msgf("wait %s before starting the worker", config.WorkerDelay)
time.Sleep(config.WorkerDelay)
}
l.Info().Msg("starting worker now")
// Signal that worker is starting
close(workerStarted)
count, uniques := run(ctx, config, durations)
close(durations)
ch <- count
ch <- uniques
}()
// Wait for worker to start, then give it time to register workflows
<-workerStarted
time.Sleep(after)
scheduled := make(chan time.Duration, config.Events)
// Compute running average for scheduled times using a rolling average.
scheduledResult := make(chan avgResult)
go func() {
var count int64
var avg time.Duration
for d := range scheduled {
count++
if count == 1 {
avg = d
} else {
avg += (d - avg) / time.Duration(count)
}
}
scheduledResult <- avgResult{count: count, avg: avg}
}()
emitted := emit(ctx, config.Namespace, config.Events, config.Duration, scheduled, config.PayloadSize)
close(scheduled)
executed := <-ch
uniques := <-ch
finalDurationResult := <-durationsResult
finalScheduledResult := <-scheduledResult
log.Printf(" emitted %d, executed %d, uniques %d, using %d events/s", emitted, executed, uniques, config.Events)
if executed == 0 {
return fmt.Errorf("❌ no events executed")
}
log.Printf(" final average duration per executed event: %s", finalDurationResult.avg)
log.Printf(" final average scheduling time per event: %s", finalScheduledResult.avg)
if int64(config.EventFanout)*emitted*int64(config.DagSteps) != executed {
log.Printf("⚠️ warning: emitted and executed counts do not match: %d != %d", int64(config.EventFanout)*emitted*int64(config.DagSteps), executed)
}
if int64(config.EventFanout)*emitted*int64(config.DagSteps) != uniques {
return fmt.Errorf("❌ emitted and unique executed counts do not match: %d != %d", int64(config.EventFanout)*emitted, uniques)
}
log.Printf("✅ success")
return nil
}