launce

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Apr 1, 2024 License: Apache-2.0 Imports: 21 Imported by: 0

README

launce

Launce is a Locust worker library written in Go. The aim of this library is to write load test scenarios as simply as locustfile.py and to run load testing with better performance.

Supported Features

Locust Feature Supported Example
WorkerRunner Yes _examples/simple-user
MasterRunner No
LocalRunner No
User Yes _examples/simple-user
HttpUser No
TaskSet Yes _examples/taskset
SequentialTaskSet Yes _examples/taskset
tag decorator Yes _examples/tagged-task
wait_time functions Yes
custom messages Yes _examples/custom-messages
custom arguments Yes _examples/custom-arguments

Install

go get github.com/qitoi/launce

Usage

You need to write two scripts, a master script and a worker script.

Master Script

Master script must define user class, but is not meant to implement user behavior.

# locustfile.py
from locust import User, task

class MyUser(User):
    @task
    def dummy(self):
        ...
Worker Script

Worker script is where you implement the actual load test scenario.

// main.go
package main

import (
	"context"
	"errors"
	"io"
	"log"
	"net/http"
	"os/signal"
	"syscall"
	"time"

	"github.com/qitoi/launce"
)

var (
	_ launce.BaseUser = (*MyUser)(nil)
)

// MyUser implements custom user behavior for load testing
type MyUser struct {
	// Inherits default methods from BaseUserImpl
	launce.BaseUserImpl
	host   string
	client *http.Client
}

// WaitTime defines how long the user waits by Wait method
func (u *MyUser) WaitTime() launce.WaitTimeFunc {
	return launce.Constant(1 * time.Second)
}

// OnStart is called when the user starts
func (u *MyUser) OnStart(ctx context.Context) error {
	u.host = u.Runner().Host()
	u.client = &http.Client{}
	return nil
}

// Process defines user action
func (u *MyUser) Process(ctx context.Context) error {
	if err := u.request(http.MethodGet, "/hello"); err != nil {
		return err
	}

	if err := u.Wait(ctx); err != nil {
		return err
	}

	return nil
}

func (u *MyUser) request(method, path string) error {
	req, err := http.NewRequest(method, u.host+path, nil)
	if err != nil {
		return err
	}

	t := time.Now()

	res, err := u.client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	// count response size
	size, err := io.Copy(io.Discard, res.Body)
	if err != nil {
		return err
	}

	responseTime := time.Since(t)

	var resErr error
	if 400 <= res.StatusCode && res.StatusCode < 600 {
		resErr = errors.New("unexpected response status code")
	}

	// report stats of a request to master
	u.Report(method, path, responseTime, size, resErr)

	return nil
}

func main() {
	// initializes a ZeroMQ transport for communication with the Locust master
	transport := launce.NewZmqTransport("localhost", 5557)
	// create worker
	worker, err := launce.NewWorker(transport)
	if err != nil {
		log.Fatal(err)
	}

	// register user
	worker.RegisterUser("MyUser", func() launce.User {
		return &MyUser{}
	})

	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	go func() {
		<-ctx.Done()
		worker.Quit()
	}()

	// start worker
	if err := worker.Join(); err != nil {
		log.Fatal(err)
	}
}

Run master and worker.

# run Locust master
locust --master -f locustfile.py

# run Locust worker by launce (in another terminal)
go run .

License

Apache License 2.0

Copyright 2024 qitoi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Documentation

Overview

Package launce is Locust worker library written in Go. The aim of this library is to write load test scenarios as simply as locustfile.py and to run load testing with better performance.

Index

Constants

View Source
const (
	// Version is the version of launce.
	Version = "1.0.1"

	// LocustVersion is the version of locust that launce is compatible with.
	LocustVersion = "2.24.1"
)
View Source
const (
	// NoneResponseTime is a special value that represents no response time.
	NoneResponseTime = time.Duration(-1)
)

Variables

View Source
var (
	ErrConnection = errors.New("failed to connect to master")
)
View Source
var (
	// StopUser is an error that stops the user.
	StopUser = errors.New("stop user")
)

Functions

func Wrap

func Wrap(err error) error

Wrap returns error with stack trace.

Types

type BaseUser

type BaseUser interface {
	User
	WaitTime() WaitTimeFunc
}

BaseUser is the interface that structs must implement to use BaseUserImpl.

type BaseUserImpl

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

BaseUserImpl is a base implementation of User.

func (*BaseUserImpl) Init

func (b *BaseUserImpl) Init(u User, r Runner, rep Reporter)

Init initializes the user.

func (*BaseUserImpl) OnStart

func (b *BaseUserImpl) OnStart(ctx context.Context) error

OnStart is called when the user starts.

func (*BaseUserImpl) OnStop

func (b *BaseUserImpl) OnStop(ctx context.Context) error

OnStop is called when the user stops.

func (*BaseUserImpl) Report

func (b *BaseUserImpl) Report(requestType, name string, responseTime time.Duration, contentLength int64, err error)

Report reports the result of a request.

func (*BaseUserImpl) Runner

func (b *BaseUserImpl) Runner() Runner

Runner returns the generator.

func (*BaseUserImpl) Wait

func (b *BaseUserImpl) Wait(ctx context.Context) error

Wait waits for the time returned by WaitTime.

type LoadGenerator

type LoadGenerator struct {
	// RestartMode is the mode of spawning users.
	RestartMode spawner.RestartMode

	// StatsNotifyInterval is the interval to notify stats.
	StatsNotifyInterval time.Duration
	// contains filtered or unexported fields
}

LoadGenerator is an instance of load test generator.

func NewLoadGenerator

func NewLoadGenerator() *LoadGenerator

NewLoadGenerator returns a new LoadGenerator.

func (*LoadGenerator) OnTestStart

func (l *LoadGenerator) OnTestStart(f func(ctx context.Context) error)

OnTestStart registers a function to be called when the load test starts.

func (*LoadGenerator) OnTestStop

func (l *LoadGenerator) OnTestStop(f func(ctx context.Context))

OnTestStop registers a function to be called when the load test stops.

func (*LoadGenerator) OnTestStopping

func (l *LoadGenerator) OnTestStopping(f func(ctx context.Context))

OnTestStopping registers a function to be called when the load test start stopping.

func (*LoadGenerator) RegisterUser

func (l *LoadGenerator) RegisterUser(r Runner, name string, f func() User)

RegisterUser registers a user class.

func (*LoadGenerator) Spawn

func (l *LoadGenerator) Spawn(user string, count int) error

Spawn spawns users.

func (*LoadGenerator) Start

func (l *LoadGenerator) Start() error

Start starts the load test.

func (*LoadGenerator) Stats

func (l *LoadGenerator) Stats() <-chan *stats.Stats

Stats returns the stats channel.

func (*LoadGenerator) Stop

func (l *LoadGenerator) Stop()

Stop stops the load test.

func (*LoadGenerator) StopUsers

func (l *LoadGenerator) StopUsers()

StopUsers stops all users.

func (*LoadGenerator) Users

func (l *LoadGenerator) Users() map[string]int64

Users returns the number of running users.

type Message

type Message struct {
	Type   string
	Data   msgpack.RawMessage
	NodeID string
}

func (*Message) DecodePayload

func (r *Message) DecodePayload(v interface{}) error

type MessageHandler

type MessageHandler func(msg Message)

MessageHandler defines a function to handle custom messages from the master.

type ParsedOptions

type ParsedOptions struct {
	// Common Options
	Locustfile   string    `msgpack:"locustfile"`    // --locustfile
	Config       string    `msgpack:"config"`        // --config
	Host         string    `msgpack:"host"`          // --host
	NumUsers     *int64    `msgpack:"num_users"`     // --users
	SpawnRate    *float64  `msgpack:"spawn_rate"`    // --spawn-rate
	HatchRate    int64     `msgpack:"hatch_rate"`    // --hatch-rate
	RunTime      *int64    `msgpack:"run_time"`      // --run-time
	ListCommands bool      `msgpack:"list_commands"` // --list
	ConfigUsers  *[]string `msgpack:"config_users"`  // --config-users

	// Web UI Options
	WebHost     string  `msgpack:"web_host"`     // --web-host
	WebPort     int64   `msgpack:"web_port"`     // --web-port
	Headless    bool    `msgpack:"headless"`     // --headless
	Autostart   bool    `msgpack:"autostart"`    // --autostart
	Autoquit    int64   `msgpack:"autoquit"`     // --autoquit
	Headful     bool    `msgpack:"headful"`      // --headful
	WebAuth     *string `msgpack:"web_auth"`     // --web-auth
	WebLogin    bool    `msgpack:"web_login"`    // --web-login
	TLSCert     string  `msgpack:"tls_cert"`     // --tls-key
	TLSKey      string  `msgpack:"tls_key"`      // --tls-cert
	ClassPicker bool    `msgpack:"class_picker"` // --class-picker
	LegacyUI    bool    `msgpack:"legacy_ui"`    // --legacy-ui

	// Master Options
	Master               bool   `msgpack:"master"`                  // --master
	MasterBindHost       string `msgpack:"master_bind_host"`        // --master-bind-host
	MasterBindPort       int64  `msgpack:"master_bind_port"`        // --master-bind-port
	ExpectWorkers        int64  `msgpack:"expect_workers"`          // --expect-workers
	ExpectWorkersMaxWait int64  `msgpack:"expect_workers_max_wait"` // --expect-worker-max-wait
	EnableRebalancing    bool   `msgpack:"enable_rebalancing"`      // --enable-rebalancing
	ExpectSlaves         bool   `msgpack:"expect_slaves"`           // --expect-slaves

	// Worker Options
	Worker     bool   `msgpack:"worker"`      // --worker
	Processes  *int64 `msgpack:"processes"`   // --processes
	Slave      bool   `msgpack:"slave"`       // --slave
	MasterHost string `msgpack:"master_host"` // --master-host
	MasterPort int    `msgpack:"master_port"` // --master-port

	// Tag Options
	Tags        *[]string `msgpack:"tags"`         // --tags
	ExcludeTags *[]string `msgpack:"exclude_tags"` // --exclude-tags

	// Stats Options
	CsvPrefix           *string `msgpack:"csv_prefix"`            // --csv
	StatsHistoryEnabled bool    `msgpack:"stats_history_enabled"` // --csv-full-history
	PrintStats          bool    `msgpack:"print_stats"`           // --print-stats
	OnlySummary         bool    `msgpack:"only_summary"`          // --only-summary
	ResetStats          bool    `msgpack:"reset_stats"`           // --reset-stats
	HtmlFile            *string `msgpack:"html_file"`             // --html
	Json                bool    `msgpack:"json"`                  // --json

	// Log Options
	SkipLogSetup bool    `msgpack:"skip_log_setup"` // --skip-log-setup
	Loglevel     string  `msgpack:"loglevel"`       // --loglevel
	Logfile      *string `msgpack:"logfile"`        // --logfile

	// Other Options
	ShowTaskRatio     bool  `msgpack:"show_task_ratio"`      // --show-task-ratio
	ShowTaskRatioJson bool  `msgpack:"show_task_ratio_json"` // --show-task-ratio-json
	ExitCodeOnError   int64 `msgpack:"exit_code_on_error"`   // --exit-code-on-error
	StopTimeout       int64 `msgpack:"stop_timeout"`         // --stop-timeout
	EqualWeights      bool  `msgpack:"equal_weights"`        // --equal-weights

	// User Classes Options
	UserClasses []string `msgpack:"user_classes"` // <UserClass1 UserClass2>
	// contains filtered or unexported fields
}

ParsedOptions is the command line options of locust.

func (*ParsedOptions) DecodeMsgpack

func (p *ParsedOptions) DecodeMsgpack(dec *msgpack.Decoder) error

DecodeMsgpack decodes the msgpack data.

func (*ParsedOptions) Extract

func (p *ParsedOptions) Extract(v interface{}) error

Extract extracts the parsed options to the given value.

type Reporter

type Reporter interface {
	Report(requestType, name string, responseTime time.Duration, contentLength int64, err error)
}

Reporter is the interface that reports the result of a request.

type Runner

type Runner interface {
	Host() string
	Tags() (tags, excludeTags *[]string)

	Options(v interface{}) error

	RegisterMessage(typ string, handler MessageHandler)
	SendMessage(typ string, data any) error

	ReportException(err error)
}

Runner is interface for load test runner.

type Transport

type Transport interface {
	// Open opens the connection to the master.
	Open(ctx context.Context, clientID string) error
	// Close closes the connection to the master.
	Close() error
	// Send sends a message to the master.
	Send(msg []byte) error
	// Receive receives a message from the master.
	Receive() ([]byte, error)
}

Transport is the interface that communicates with the master.

type UnknownUserError

type UnknownUserError struct {
	User string
}

UnknownUserError is an error that trying to spawn unregistered user.

func (*UnknownUserError) Error

func (e *UnknownUserError) Error() string

type User

type User interface {
	Reporter

	Init(u User, r Runner, rep Reporter)
	Runner() Runner
	OnStart(ctx context.Context) error
	OnStop(ctx context.Context) error
	Process(ctx context.Context) error
	Wait(ctx context.Context) error
}

User is the interface that behaves as a locust user.

type WaitTimeFunc

type WaitTimeFunc func() time.Duration

WaitTimeFunc represents a wait time function for users or tasks.

func Between

func Between(min, max time.Duration) WaitTimeFunc

Between returns a WaitTimeFunc that returns a random wait time between min and max.

func Constant

func Constant(d time.Duration) WaitTimeFunc

Constant returns a WaitTimeFunc that returns the constant wait time.

func ConstantPacing

func ConstantPacing(d time.Duration) WaitTimeFunc

ConstantPacing returns a WaitTimeFunc that calculates wait time to ensure the interval between task executions is d.

func ConstantThroughput

func ConstantThroughput(taskRunsPerSecond float64) WaitTimeFunc

ConstantThroughput returns a WaitTimeFunc that returns wait time that makes the number of task executions per second equal to taskRunsPerSecond.

type Worker

type Worker struct {
	// Version is the version of the worker
	Version string

	// ClientID is the unique identifier of the worker.
	ClientID string

	// HeartbeatInterval is the interval at which the worker sends a heartbeat message to the master.
	HeartbeatInterval time.Duration

	// MasterHeartbeatTimeout is the timeout for the heartbeat from the master.
	MasterHeartbeatTimeout time.Duration

	// MetricsMonitorInterval is the interval at which the worker monitors the process metrics.
	MetricsMonitorInterval time.Duration

	// StatsReportInterval is the interval at which the worker sends statistics to the master.
	StatsReportInterval time.Duration

	// StatsAggregateInterval is the interval at which the worker aggregates statistics of users.
	StatsAggregateInterval time.Duration
	// contains filtered or unexported fields
}

Worker provides the functionality of a Locust worker.

func NewWorker

func NewWorker(transport Transport) (*Worker, error)

NewWorker creates an instance of Worker.

func (*Worker) Host

func (w *Worker) Host() string

func (*Worker) Index

func (w *Worker) Index() int64

Index returns the index of the worker.

func (*Worker) Join

func (w *Worker) Join() error

Join connects to the master and starts the worker processes.

func (*Worker) OnConnect

func (w *Worker) OnConnect(f func())

OnConnect registers function to be called when the worker connects to the master.

func (*Worker) OnQuit

func (w *Worker) OnQuit(f func())

OnQuit registers function to be called when the worker quits.

func (*Worker) OnQuitting

func (w *Worker) OnQuitting(f func())

OnQuitting registers function to be called when the worker starts quitting.

func (*Worker) OnTestStart

func (w *Worker) OnTestStart(f func(ctx context.Context) error)

OnTestStart registers function to be called when the test starts.

func (*Worker) OnTestStop

func (w *Worker) OnTestStop(f func(ctx context.Context))

OnTestStop registers function to be called when the test stops.

func (*Worker) OnTestStopping

func (w *Worker) OnTestStopping(f func(ctx context.Context))

OnTestStopping registers function to be called when the load test start stopping.

func (*Worker) Options

func (w *Worker) Options(v interface{}) error

func (*Worker) Quit

func (w *Worker) Quit()

Quit stops the worker.

func (*Worker) RegisterMessage

func (w *Worker) RegisterMessage(typ string, handler MessageHandler)

RegisterMessage registers custom message handler.

func (*Worker) RegisterUser

func (w *Worker) RegisterUser(name string, f func() User)

RegisterUser registers user.

func (*Worker) ReportException

func (w *Worker) ReportException(err error)

func (*Worker) SendMessage

func (w *Worker) SendMessage(typ string, data any) error

SendMessage sends message to the master.

func (*Worker) State

func (w *Worker) State() WorkerState

State returns the state of the worker.

func (*Worker) Stop

func (w *Worker) Stop()

Stop stops the load test.

func (*Worker) Tags

func (w *Worker) Tags() (tags, excludeTags *[]string)

type WorkerState

type WorkerState = int64
const (
	WorkerStateInit WorkerState = iota
	WorkerStateSpawning
	WorkerStateRunning
	WorkerStateCleanup
	WorkerStateStopped
)

type ZmqTransport

type ZmqTransport struct {
	Host string
	Port int
	// contains filtered or unexported fields
}

ZmqTransport is transport that uses ZeroMQ.

func NewZmqTransport

func NewZmqTransport(host string, port int, opts ...zmq4.Option) *ZmqTransport

NewZmqTransport returns a new ZmqTransport.

func (*ZmqTransport) Close

func (t *ZmqTransport) Close() error

Close closes the connection to the master.

func (*ZmqTransport) Open

func (t *ZmqTransport) Open(ctx context.Context, clientID string) error

Open opens the connection to the master.

func (*ZmqTransport) Receive

func (t *ZmqTransport) Receive() ([]byte, error)

Receive receives a message from the master.

func (*ZmqTransport) Send

func (t *ZmqTransport) Send(msg []byte) error

Send sends a message to the master.

Directories

Path Synopsis
_examples
Package spawner implements dynamic goroutine management.
Package spawner implements dynamic goroutine management.
Package stats implements statistics for Locust.
Package stats implements statistics for Locust.
Package taskset implements utilities for structured test scenarios.
Package taskset implements utilities for structured test scenarios.

Jump to

Keyboard shortcuts

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