mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-05 07:26:55 +08:00
feat: add boomer state
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
- feat: report GA events with version
|
- feat: report GA events with version
|
||||||
- feat: run load test with the given limit and burst as rate limiter
|
- feat: run load test with the given limit and burst as rate limiter
|
||||||
- change: update API models
|
- change: update API models
|
||||||
|
- feat: report runner state
|
||||||
|
|
||||||
## v0.2.2 (2021-12-07)
|
## v0.2.2 (2021-12-07)
|
||||||
|
|
||||||
|
|||||||
@@ -125,8 +125,8 @@ func (o *ConsoleOutput) OnEvent(data map[string]interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
println(fmt.Sprintf("Current time: %s, Users: %d, Total RPS: %d, Total Fail Ratio: %.1f%%",
|
println(fmt.Sprintf("Current time: %s, Users: %d, State: %d, Total RPS: %d, Total Fail Ratio: %.1f%%",
|
||||||
currentTime.Format("2006/01/02 15:04:05"), output.UserCount, output.TotalRPS, output.TotalFailRatio*100))
|
currentTime.Format("2006/01/02 15:04:05"), output.UserCount, output.State, output.TotalRPS, output.TotalFailRatio*100))
|
||||||
println(fmt.Sprintf("Accumulated Transactions: %d Passed, %d Failed",
|
println(fmt.Sprintf("Accumulated Transactions: %d Passed, %d Failed",
|
||||||
output.TransactionsPassed, output.TransactionsFailed))
|
output.TransactionsPassed, output.TransactionsFailed))
|
||||||
table := tablewriter.NewWriter(os.Stdout)
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
@@ -163,6 +163,7 @@ type statsEntryOutput struct {
|
|||||||
|
|
||||||
type dataOutput struct {
|
type dataOutput struct {
|
||||||
UserCount int32 `json:"user_count"`
|
UserCount int32 `json:"user_count"`
|
||||||
|
State int32 `json:"state"`
|
||||||
TotalStats *statsEntryOutput `json:"stats_total"`
|
TotalStats *statsEntryOutput `json:"stats_total"`
|
||||||
TransactionsPassed int64 `json:"transactions_passed"`
|
TransactionsPassed int64 `json:"transactions_passed"`
|
||||||
TransactionsFailed int64 `json:"transactions_failed"`
|
TransactionsFailed int64 `json:"transactions_failed"`
|
||||||
@@ -177,6 +178,10 @@ func convertData(data map[string]interface{}) (output *dataOutput, err error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("user_count is not int32")
|
return nil, fmt.Errorf("user_count is not int32")
|
||||||
}
|
}
|
||||||
|
state, ok := data["state"].(int32)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("state is not int32")
|
||||||
|
}
|
||||||
stats, ok := data["stats"].([]interface{})
|
stats, ok := data["stats"].([]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("stats is not []interface{}")
|
return nil, fmt.Errorf("stats is not []interface{}")
|
||||||
@@ -201,6 +206,7 @@ func convertData(data map[string]interface{}) (output *dataOutput, err error) {
|
|||||||
|
|
||||||
output = &dataOutput{
|
output = &dataOutput{
|
||||||
UserCount: userCount,
|
UserCount: userCount,
|
||||||
|
State: state,
|
||||||
TotalStats: entryTotalOutput,
|
TotalStats: entryTotalOutput,
|
||||||
TransactionsPassed: transactionsPassed,
|
TransactionsPassed: transactionsPassed,
|
||||||
TransactionsFailed: transactionsFailed,
|
TransactionsFailed: transactionsFailed,
|
||||||
@@ -321,6 +327,12 @@ var (
|
|||||||
Help: "The current number of users",
|
Help: "The current number of users",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
gaugeState = prometheus.NewGauge(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "state",
|
||||||
|
Help: "The current runner state, 1=initializing, 2=spawning, 3=running, 4=quitting, 5=stopped",
|
||||||
|
},
|
||||||
|
)
|
||||||
gaugeTotalRPS = prometheus.NewGauge(
|
gaugeTotalRPS = prometheus.NewGauge(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Name: "total_rps",
|
Name: "total_rps",
|
||||||
@@ -377,6 +389,7 @@ func (o *PrometheusPusherOutput) OnStart() {
|
|||||||
gaugeCurrentFailPerSec,
|
gaugeCurrentFailPerSec,
|
||||||
// gauges for total
|
// gauges for total
|
||||||
gaugeUsers,
|
gaugeUsers,
|
||||||
|
gaugeState,
|
||||||
gaugeTotalRPS,
|
gaugeTotalRPS,
|
||||||
gaugeTotalFailRatio,
|
gaugeTotalFailRatio,
|
||||||
gaugeTransactionsPassed,
|
gaugeTransactionsPassed,
|
||||||
@@ -401,6 +414,9 @@ func (o *PrometheusPusherOutput) OnEvent(data map[string]interface{}) {
|
|||||||
// user count
|
// user count
|
||||||
gaugeUsers.Set(float64(output.UserCount))
|
gaugeUsers.Set(float64(output.UserCount))
|
||||||
|
|
||||||
|
// runner state
|
||||||
|
gaugeState.Set(float64(output.State))
|
||||||
|
|
||||||
// rps in total
|
// rps in total
|
||||||
gaugeTotalRPS.Set(float64(output.TotalRPS))
|
gaugeTotalRPS.Set(float64(output.TotalRPS))
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
stateInit = "ready"
|
stateInit = iota + 1 // initializing
|
||||||
stateSpawning = "spawning"
|
stateSpawning // spawning
|
||||||
stateRunning = "running"
|
stateRunning // running
|
||||||
stateStopped = "stopped"
|
stateQuitting // quitting
|
||||||
stateQuitting = "quitting"
|
stateStopped // stopped
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -25,7 +25,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type runner struct {
|
type runner struct {
|
||||||
state string
|
state int32
|
||||||
|
|
||||||
tasks []*Task
|
tasks []*Task
|
||||||
totalTaskWeight int
|
totalTaskWeight int
|
||||||
@@ -116,6 +116,7 @@ func (r *runner) spawnWorkers(spawnCount int, spawnRate float64, quit chan bool,
|
|||||||
Float64("spawnRate", spawnRate).
|
Float64("spawnRate", spawnRate).
|
||||||
Msg("Spawning workers")
|
Msg("Spawning workers")
|
||||||
|
|
||||||
|
atomic.StoreInt32(&r.state, stateSpawning)
|
||||||
// TODO: spawn workers with spawnRate
|
// TODO: spawn workers with spawnRate
|
||||||
for i := 1; i <= spawnCount; i++ {
|
for i := 1; i <= spawnCount; i++ {
|
||||||
select {
|
select {
|
||||||
@@ -150,6 +151,7 @@ func (r *runner) spawnWorkers(spawnCount int, spawnRate float64, quit chan bool,
|
|||||||
if spawnCompleteFunc != nil {
|
if spawnCompleteFunc != nil {
|
||||||
spawnCompleteFunc()
|
spawnCompleteFunc()
|
||||||
}
|
}
|
||||||
|
atomic.StoreInt32(&r.state, stateRunning)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setTasks will set the runner's task list AND the total task weight
|
// setTasks will set the runner's task list AND the total task weight
|
||||||
@@ -217,7 +219,7 @@ func newLocalRunner(tasks []*Task, rateLimiter RateLimiter, spawnCount int, spaw
|
|||||||
|
|
||||||
func (r *localRunner) start() {
|
func (r *localRunner) start() {
|
||||||
// init state
|
// init state
|
||||||
r.state = stateInit
|
atomic.StoreInt32(&r.state, stateInit)
|
||||||
atomic.StoreInt32(&r.currentClientsNum, 0)
|
atomic.StoreInt32(&r.currentClientsNum, 0)
|
||||||
r.stats.clearAll()
|
r.stats.clearAll()
|
||||||
|
|
||||||
@@ -248,6 +250,7 @@ func (r *localRunner) start() {
|
|||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
data := r.stats.collectReportData()
|
data := r.stats.collectReportData()
|
||||||
data["user_count"] = atomic.LoadInt32(&r.currentClientsNum)
|
data["user_count"] = atomic.LoadInt32(&r.currentClientsNum)
|
||||||
|
data["state"] = atomic.LoadInt32(&r.state)
|
||||||
r.outputOnEevent(data)
|
r.outputOnEevent(data)
|
||||||
case <-r.stopChan:
|
case <-r.stopChan:
|
||||||
// stop previous goroutines without blocking
|
// stop previous goroutines without blocking
|
||||||
@@ -265,5 +268,7 @@ func (r *localRunner) start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *localRunner) stop() {
|
func (r *localRunner) stop() {
|
||||||
|
atomic.StoreInt32(&r.state, stateQuitting)
|
||||||
close(r.stopChan)
|
close(r.stopChan)
|
||||||
|
atomic.StoreInt32(&r.state, stateStopped)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user