engine

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

Package engine executes a load profile inside one worker process.

It owns the virtual user pool: starting goroutines as the profile ramps up, stopping them as it ramps down, and driving each one through its scenario in a loop. Everything above it — agents, the coordinator, the dashboard — deals in quotas and aggregates; this is the only layer that runs user code.

Index

Constants

View Source
const DefaultGracefulStop = 30 * time.Second

DefaultGracefulStop is how long in-flight iterations get to finish when a run ends, if the plan does not say.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	RunID  string
	NodeID string

	Plan     *loadwavev1.TestPlan
	Registry *loadwave.Registry
	Recorder *metrics.Recorder
	HTTP     *loadwave.HTTPClientFactory
	Logger   *slog.Logger

	// StartAt is the instant, agreed across the whole fleet, that elapsed
	// time is measured from. The engine idles until it arrives, so that nodes
	// which received their orders at different moments still ramp together.
	StartAt time.Time

	// VUQuota is this node's virtual user count at the profile's peak.
	VUQuota int

	// IterationRateQuota caps iterations started per second on this node.
	// Zero means unlimited.
	IterationRateQuota int

	// IterationQuota stops this node after this many completed iterations.
	// Zero means unbounded.
	IterationQuota uint64

	// VUIDBase is the first virtual user id this node may allocate.
	VUIDBase int64

	// Shard identifies this node's slice of shared fixtures.
	Shard loadwave.Shard
}

Config is everything the engine needs to execute one node's share of a run.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine runs one node's share of a load profile.

func New

func New(cfg Config) (*Engine, error)

New validates the configuration and prepares the engine. It starts nothing; Run does that.

func (*Engine) ActiveVUs

func (e *Engine) ActiveVUs() int

ActiveVUs reports how many virtual users are running right now.

func (*Engine) Describe

func (e *Engine) Describe() string

Describe renders this node's share of the profile.

func (*Engine) Iterations

func (e *Engine) Iterations() uint64

Iterations reports how many iterations have completed on this node.

func (*Engine) Run

func (e *Engine) Run(ctx context.Context) error

Run executes the profile and returns when the run has finished and every virtual user has stopped.

It returns nil for a run that completed or was stopped on request, and an error only when the run could not be carried out — a scenario's Setup failing, say. A load test full of HTTP 500s is a successful run with a bad result, and the distinction matters to anything scripting this.

func (*Engine) SetQuota

func (e *Engine) SetQuota(vuQuota, iterationRateQuota int, ramp time.Duration)

SetQuota rescales this node's share while the run is in progress, either because an operator changed the target or because the fleet changed size.

A non-zero ramp introduces the change gradually rather than in one tick. The executor is mutated rather than replaced, so a change arriving mid-ramp eases from wherever the quota actually is instead of snapping back.

func (*Engine) Stop

func (e *Engine) Stop(graceful bool, reason string)

Stop ends the run. A graceful stop lets in-flight iterations finish within the plan's grace window; otherwise they are cancelled at once. Calling Stop more than once has no additional effect.

type Executor

type Executor interface {
	// TargetAt returns the desired virtual user count at an elapsed offset
	// from the run's start.
	TargetAt(elapsed time.Duration) int

	// Duration is how long the profile runs. Zero means unbounded, and the
	// run ends only on an iteration cap or an explicit stop.
	Duration() time.Duration

	// Peak is the highest virtual user count the profile ever reaches.
	Peak() int

	// Describe renders the profile for logs and the dashboard.
	Describe() string
}

Executor turns a load profile into a virtual user count at any point in a run.

It is a pure function of elapsed time, deliberately. Every node evaluates the same profile against the same agreed start instant and arrives at the same curve, so ramping needs no per-tick coordination and a node that misses messages for a few seconds rejoins the curve exactly where it should be rather than where it left off.

func NewExecutor

func NewExecutor(profile *loadwavev1.LoadProfile) (Executor, error)

NewExecutor builds the executor described by a load profile.

func Scale

func Scale(inner Executor, quota int) Executor

Scale wraps an executor so that its peak becomes quota, preserving shape.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL