pulse

package module
v0.3.7 Latest Latest
Warning

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

Go to latest
Published: May 1, 2026 License: MIT Imports: 17 Imported by: 0

README

Pulse: High-Precision Performance Testing for Algoryn Fabric

CI Go Version Latest Release License Go Reference

Pulse is a load and reliability testing tool built for the Algoryn Fabric stack. It drives HTTP workloads with predictable arrival rates, reports latency and error metrics you can trust in CI, and enforces SLOs through configurable pass/fail thresholds. The runtime combines Go for high-throughput orchestration and C++ for constant-memory, high-dynamic-range (HDR) latency histograms, so performance metrics stay accurate and lightweight even on long, heavy runs.


Architecture highlights

Hybrid engine
  • Go — Schedules load across constant, ramp, step, and spike phases, bounds concurrency with a limiter, and runs scenarios at the target requests-per-second. This layer is where scale and determinism come from: token-bucket pacing, goroutine lifecycle, and the pulse / library API.
  • C++ (via cgo) — A native HDR-style logarithmic histogram records every latency sample in O(1) time with a fixed bucket count. The engine covers roughly 1 microsecond to 60 seconds on a single run with sub-microsecond resolution in the low-latency regime and a stable, constant memory footprint (no unbounded per-sample storage in the hot path). Percentiles (P50, P90, P95, P99) are derived from that histogram, then combined in Go with exact min, max, and mean tracking.

This split keeps the scheduler and network I/O in idiomatic, concurrent Go while entrusting percentile math to a compact, allocation-friendly path suited to long campaigns and high sample counts.

Fabric integration

Pulse depends on algoryn.io/fabric v0.2.0+ for shared contracts, including Protocol Buffer messages under algoryn.io/fabric/gen/go/fabric/v1.

  • ToRunEvent maps a pulse.Result into the legacy Go types metrics.RunEvent / metrics.MetricSnapshot (algoryn.io/fabric/metrics).
  • ToRunEventProto returns the same data as fabric.v1.RunEvent (with fabric.v1.MetricSnapshot inside), using Fabric’s RunEventToProto helper so timestamps are google.protobuf.Timestamp.
  • ToFabricRunEmit returns a matched pair: the full RunEvent protobuf and a fabric.v1.Event with EVENT_TYPE_RUN_COMPLETED (payload built with RunCompletedPayloadToProto), sharing one run_id so tools like Beacon can correlate summary events with detailed snapshots. The envelope timestamp uses timestamppb.Now().
  • Set Config.Service (optional) to populate MetricSnapshot.service and the run-completed payload; use Config.OnFabricEmit to receive both protobuf messages after each run (after threshold evaluation, same ordering as OnResult).

The CLI still prints human JSON for operators; wire OnFabricEmit (or call ToRunEventProto) when you need proto/binary or protojson on the wire.


Key features

Area What you get
Load model Multi-phase tests: Constant, Ramp, Step, and Spike — arrival-rate (RPS) driven, not a vague “VUs” count.
Latency P50, P90, P95, P99 (plus min, mean, max) from the C++ histogram; stable under load, bounded memory.
Configuration YAML test definitions: target, phases, maxConcurrency, and optional thresholds (error rate, mean / P95 / P99 latency).
Output Text (human-readable) and JSON (automation, CI artifacts); combine --json and --out to mirror JSON to a file.
API Use pulse.Run, OnResult hooks, optional OnFabricEmit for Fabric protobuf (RunEvent + RunCompleted event), and middleware for chaos-style scenarios; RunT for go test integration.
Tooling Optional mockserver for local demos; see examples/.

Installation

Requirements
  • Go — Version compatible with go.mod (see badge above).
  • C/C++ toolchain for cgo — Pulse links a small C++ stats library. You need a working C++17 compiler the Go toolchain can invoke:
    • macOS: Xcode Command Line Tools (clang++) are typically enough.
    • Linux: GCC or Clang with g++ / clang++ and libstdc++ or libc++ as appropriate for your distribution.

Set CC and CXX if you use a non-default compiler:

export CC=clang
export CXX=clang++
Get Pulse

From the module (for library use):

go get algoryn.io/pulse@latest

From a clone of this repository:

go install ./cmd/pulse
go install ./cmd/mockserver   # optional, for local testing

Ensure your GOBIN (or GOPATH/bin) is on PATH so the pulse binary is found.


Usage

Run a test
pulse run path/to/config.yaml

Useful flags

Flag Description
--json Print results as JSON on stdout.
--out <file> Write the same JSON object to a file (can be combined with --json).

Exit codes0 success; 2 run finished but thresholds failed; 1 for usage, config, I/O, or other failures (including mixed error types).

Sample YAML
# Steady load with latency SLOs (example: local mock server on :8080)
phases:
  - type: constant
    duration: 5s
    arrivalRate: 20

target:
  method: GET
  url: http://localhost:8080

maxConcurrency: 4

thresholds:
  maxMeanLatency: 100ms
  maxP95Latency: 150ms
  maxP99Latency: 200ms

Run against a live target or, for a quick check, start the bundled mock in another terminal: go run ./cmd/mockserver -mode healthy and point the URL at it. More examples live under examples/.

JSON result shape (summary)

The JSON report includes summary (totals, RPS, duration_ms), latency with min_ms, p50_ms, mean_ms, p90_ms, p95_ms, p99_ms, max_ms, status_codes, errors, per-threshold rows, and passed.


Ecosystem

Pulse is part of the Algoryn Fabric ecosystem: shared contracts under algoryn.io/fabric help Relay, Beacon, and other tools present and consume performance and reliability data in a consistent way. Pulse focuses on generating evidence under load; Fabric types carry that evidence to the rest of the stack.


License

MIT

Documentation

Index

Constants

View Source
const (
	// PhaseTypeConstant represents a constant arrival-rate phase.
	PhaseTypeConstant = model.PhaseTypeConstant
	// PhaseTypeRamp represents a linear ramp between two arrival rates.
	PhaseTypeRamp = model.PhaseTypeRamp
	// PhaseTypeStep represents discrete steps between two arrival rates.
	PhaseTypeStep = model.PhaseTypeStep
	// PhaseTypeSpike represents a temporary spike from a base rate to a peak rate.
	PhaseTypeSpike = model.PhaseTypeSpike
)

Variables

View Source
var (
	ErrInjected = errors.New("pulse: injected fault")
	// ErrBulkheadFull is returned by WithBulkhead when the concurrency
	// limit is reached and the context expires before a slot opens.
	ErrBulkheadFull = errors.New("pulse: bulkhead full")
)

ErrInjected is returned by WithErrorRate when a fault is injected.

View Source
var ErrCircuitOpen = errors.New("pulse: circuit open")

ErrCircuitOpen is returned when the circuit breaker is open and requests are being rejected to simulate cascading failures.

Functions

func Chain added in v0.3.3

func Chain(middlewares ...Middleware) func(Scenario) Scenario

Chain applies middlewares to a Scenario in order. The first middleware is the outermost wrapper.

func SkipIfShort added in v0.3.2

func SkipIfShort(t TB)

SkipIfShort skips the test if -short flag is set.

func ToRunEvent added in v0.3.1

func ToRunEvent(result Result, passed bool, startedAt time.Time) fabricmetrics.RunEvent

ToRunEvent converts a Pulse Result into a fabric metrics.RunEvent, making it compatible with other Algoryn ecosystem tools. The startedAt parameter should be the time the run began. If zero, time.Now() minus result.Duration is used as a best-effort approximation. Snapshot.Service is empty; use ToFabricRunEmit when you need a service name on the snapshot.

func ToRunEventProto added in v0.3.7

func ToRunEventProto(result Result, passed bool, startedAt time.Time) *fabricv1.RunEvent

ToRunEventProto converts a Pulse Result into fabric.v1.RunEvent (binary contract). Timestamps are set from startedAt / endedAt via Fabric conversion helpers (timestamppb).

Types

type Config

type Config struct {
	Phases         []Phase
	MaxConcurrency int
	Thresholds     Thresholds
	// Service is optional metadata for Fabric MetricSnapshot.Service and RunCompleted payloads.
	Service      string
	OnResult     ResultHook     // optional; nil means no-op
	OnFabricEmit FabricEmitHook // optional; protobuf RunEvent + RunCompleted Event
}

Config holds execution configuration for a test.

type FabricEmitHook added in v0.3.7

type FabricEmitHook func(run *fabricv1.RunEvent, completed *fabricv1.Event)

FabricEmitHook is invoked after threshold evaluation with protobuf contracts for the Fabric stack. run carries fabric.v1.MetricSnapshot; completed is EVENT_TYPE_RUN_COMPLETED for tools like Beacon.

type FabricRunEmit added in v0.3.7

type FabricRunEmit struct {
	RunEvent     *fabricv1.RunEvent
	RunCompleted *fabricv1.Event
}

FabricRunEmit bundles the protobuf shapes Pulse emits for downstream Algoryn tools. RunEvent carries the full MetricSnapshot; RunCompleted is the fabric.v1.Event envelope (EVENT_TYPE_RUN_COMPLETED) for consumers such as Beacon.

func ToFabricRunEmit added in v0.3.7

func ToFabricRunEmit(service string, result Result, passed bool, startedAt time.Time) FabricRunEmit

ToFabricRunEmit builds a matched pair: full RunEvent proto and a RunCompleted fabric Event sharing the same run id. RunCompleted uses timestamppb.Now() for the envelope timestamp.

type LatencyStats

type LatencyStats struct {
	Min  time.Duration
	Mean time.Duration
	P50  time.Duration
	P90  time.Duration
	P95  time.Duration
	P99  time.Duration
	Max  time.Duration
}

LatencyStats contains aggregate latency data.

type Middleware added in v0.3.3

type Middleware func(Scenario) Scenario

Middleware wraps a Scenario to add behavior before or after execution.

func WithBulkhead added in v0.3.5

func WithBulkhead(maxConcurrent int) Middleware

WithBulkhead returns a Middleware that limits the number of concurrent executions of a scenario.

func WithCircuitBreaker added in v0.3.6

func WithCircuitBreaker(threshold float64, window, timeout time.Duration) Middleware

WithCircuitBreaker returns a Middleware that simulates cascading failures by opening a circuit when the error rate within a time window exceeds the threshold.

func WithErrorRate added in v0.3.3

func WithErrorRate(rate float64) Middleware

WithErrorRate returns a Middleware that causes a percentage of requests to fail without calling the underlying Scenario.

func WithJitter added in v0.3.4

func WithJitter(min, max time.Duration, rate float64) Middleware

WithJitter returns a Middleware that adds random latency between min and max to a percentage of requests.

func WithLatency added in v0.3.3

func WithLatency(d time.Duration, rate float64) Middleware

WithLatency returns a Middleware that adds artificial latency to a percentage of requests.

func WithRetry added in v0.3.5

func WithRetry(n int, backoff time.Duration) Middleware

WithRetry returns a Middleware that retries a failed scenario up to n times with a fixed backoff between attempts.

func WithStatusCode added in v0.3.4

func WithStatusCode(code int, rate float64) Middleware

WithStatusCode returns a Middleware that forces a specific HTTP status code to be returned for a percentage of requests, without calling the underlying Scenario.

func WithTimeout added in v0.3.4

func WithTimeout(d time.Duration) Middleware

WithTimeout returns a Middleware that enforces a maximum duration for each scenario execution.

type Phase

type Phase struct {
	Type        PhaseType
	Duration    time.Duration
	ArrivalRate int
	// From and To are the arrival rates (per second) at the start and end of a ramp or step phase.
	From int
	To   int
	// Steps is the number of discrete rate levels for PhaseTypeStep.
	Steps int
	// SpikeAt is when the spike starts; 0 means immediately.
	SpikeAt time.Duration
	// SpikeDuration is how long the spike lasts.
	SpikeDuration time.Duration
}

Phase defines the minimal execution shape for the MVP.

func (Phase) IsConstant

func (p Phase) IsConstant() bool

IsConstant reports whether p is a constant arrival-rate phase.

func (Phase) IsRamp

func (p Phase) IsRamp() bool

IsRamp reports whether p is a linear ramp phase.

func (Phase) IsSpike

func (p Phase) IsSpike() bool

IsSpike reports whether p is a spike phase.

func (Phase) IsStep

func (p Phase) IsStep() bool

IsStep reports whether p is a stepped ramp phase.

type PhaseType

type PhaseType = model.PhaseType

PhaseType describes how a phase should be executed.

type Result

type Result struct {
	Total             int64
	Failed            int64
	Duration          time.Duration
	RPS               float64
	Latency           LatencyStats
	StatusCounts      map[int]int64
	ErrorCounts       map[string]int64
	ThresholdOutcomes []ThresholdOutcome `json:"-"`
}

Result contains the aggregated outcome of a test run.

func Run

func Run(test Test) (Result, error)

Run validates the test definition and executes it through the engine.

func RunT added in v0.3.2

func RunT(t TB, test Test) Result

RunT runs a Pulse load test as a Go test. It calls t.Fatal if any threshold fails or if the engine returns an error. Metrics are reported via t.Log, visible with go test -v. It returns the Result for additional assertions.

type ResultHook

type ResultHook func(result Result, passed bool)

ResultHook is an optional callback invoked after a test run completes. result contains the full aggregated metrics. passed is true when all configured thresholds were met.

type Scenario

type Scenario func(ctx context.Context) (statusCode int, err error)

Scenario is the user-defined workload executed by Pulse. The int is an HTTP or application status code; use 0 when not applicable.

func Apply added in v0.3.3

func Apply(scenario Scenario, middlewares ...Middleware) Scenario

Apply wraps a Scenario with the given middlewares.

type TB added in v0.3.2

type TB interface {
	Helper()
	Fatalf(format string, args ...any)
	Logf(format string, args ...any)
	Skip(args ...any)
}

TB is the minimal testing interface required by Pulse helpers.

type Test

type Test struct {
	Config   Config
	Scenario Scenario
}

Test is the root public input for a Pulse run.

type ThresholdOutcome

type ThresholdOutcome struct {
	Pass        bool
	Description string
}

ThresholdOutcome records whether a configured threshold passed for a run.

type ThresholdViolationError

type ThresholdViolationError struct {
	Description string
	Actual      any
	Limit       any
}

ThresholdViolationError is returned when a configured threshold is exceeded. Description matches the corresponding ThresholdOutcome description (e.g. "mean_latency < 200ms").

func (*ThresholdViolationError) Error

func (e *ThresholdViolationError) Error() string

type Thresholds

type Thresholds struct {
	ErrorRate      float64
	MaxMeanLatency time.Duration
	MaxP95Latency  time.Duration
	MaxP99Latency  time.Duration
}

Thresholds define basic pass/fail conditions for a run.

Directories

Path Synopsis
cmd
mockserver command
pulse command

Jump to

Keyboard shortcuts

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