From 3aa39d908a98b8f351f7e69c2bc0c45cca65dcc9 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Fri, 29 Nov 2024 11:33:59 -0800 Subject: [PATCH] [v1.4.2] Introduce normalized latency distribution --- internal/http/math.go | 24 ++++++++++++++++++++++++ internal/http/server.go | 30 +++++++++++++++++++++++------- internal/settings/settings.go | 2 ++ 3 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 internal/http/math.go diff --git a/internal/http/math.go b/internal/http/math.go new file mode 100644 index 0000000..266500f --- /dev/null +++ b/internal/http/math.go @@ -0,0 +1,24 @@ +package http + +import ( + "math/rand" + "time" +) + +type normalDistribution struct { + mean float64 + stddev float64 +} + +func newNormalDistribution(mean, stddev uint64) *normalDistribution { + return &normalDistribution{mean: float64(mean), stddev: float64(stddev)} +} + +func (n *normalDistribution) latency() time.Duration { + ms := n.mean + rand.NormFloat64()*n.stddev + if ms < 0 { + return 0 + } + + return time.Duration(ms) * time.Millisecond +} diff --git a/internal/http/server.go b/internal/http/server.go index e73d348..d144157 100644 --- a/internal/http/server.go +++ b/internal/http/server.go @@ -5,6 +5,7 @@ import ( "log/slog" "net/http" "sync/atomic" + "time" "go.uber.org/fx" @@ -18,21 +19,36 @@ var Module = fx.Options( func ProvideServer(s *settings.Values, l *slog.Logger) *Server { return &Server{ - counter: &atomic.Uint64{}, - frequency: s.CrashFrequency, - logger: l, + counter: &atomic.Uint64{}, + frequency: s.CrashFrequency, + logger: l, + latencyGen: newNormalDistribution(s.LatencyMean, s.LatencyStddev), } } type Server struct { - counter *atomic.Uint64 - frequency uint64 - logger *slog.Logger + counter *atomic.Uint64 + frequency uint64 + logger *slog.Logger + latencyGen *normalDistribution } func (s *Server) HandleHTTP(w http.ResponseWriter, r *http.Request) { - s.logger.Info("inbound", "method", r.Method, "url", r.URL.Path, "host", r.Host, "proto", r.Proto, "agent", r.UserAgent(), "peer", r.RemoteAddr, "counter", s.counter.Load()) newCount := s.counter.Add(1) + latency := s.latencyGen.latency() + + s.logger.Info("inbound", + "method", r.Method, + "url", r.URL.Path, + "host", r.Host, + "proto", r.Proto, + "agent", r.UserAgent(), + "peer", r.RemoteAddr, + "counter", newCount, + "latency", latency, + ) + + time.Sleep(s.latencyGen.latency()) if s.frequency != 0 && newCount%s.frequency == 0 { s.logger.Warn("crash", "counter", newCount) diff --git a/internal/settings/settings.go b/internal/settings/settings.go index d67534c..0887db4 100644 --- a/internal/settings/settings.go +++ b/internal/settings/settings.go @@ -11,6 +11,8 @@ var Module = fx.Provide(ProvideSettings) type Values struct { CrashFrequency uint64 `env:"HTTP_CRASH_FREQUENCY" envDefault:"10"` // Set to zero to disable + LatencyMean uint64 `env:"HTTP_LATENCY_MEAN" envDefault:"50"` + LatencyStddev uint64 `env:"HTTP_LATENCY_STDDEV" envDefault:"25"` } func ProvideSettings() (*Values, error) {