Merge pull request #54 from xucong053/main

fix: ensure last stats to be reported
This commit is contained in:
debugtalk
2022-01-13 18:35:10 +08:00
committed by GitHub
2 changed files with 45 additions and 35 deletions

View File

@@ -65,6 +65,7 @@ func init() {
boomCmd.Flags().StringVar(&requestIncreaseRate, "request-increase-rate", "-1", "Request increase rate, disabled by default.") boomCmd.Flags().StringVar(&requestIncreaseRate, "request-increase-rate", "-1", "Request increase rate, disabled by default.")
boomCmd.Flags().IntVar(&spawnCount, "spawn-count", 1, "The number of users to spawn for load testing") boomCmd.Flags().IntVar(&spawnCount, "spawn-count", 1, "The number of users to spawn for load testing")
boomCmd.Flags().Float64Var(&spawnRate, "spawn-rate", 1, "The rate for spawning users") boomCmd.Flags().Float64Var(&spawnRate, "spawn-rate", 1, "The rate for spawning users")
boomCmd.Flags().Int64Var(&loopCount, "loop-count", -1, "The specify running cycles for load testing")
boomCmd.Flags().StringVar(&memoryProfile, "mem-profile", "", "Enable memory profiling.") boomCmd.Flags().StringVar(&memoryProfile, "mem-profile", "", "Enable memory profiling.")
boomCmd.Flags().DurationVar(&memoryProfileDuration, "mem-profile-duration", 30*time.Second, "Memory profile duration.") boomCmd.Flags().DurationVar(&memoryProfileDuration, "mem-profile-duration", 30*time.Second, "Memory profile duration.")
boomCmd.Flags().StringVar(&cpuProfile, "cpu-profile", "", "Enable CPU profiling.") boomCmd.Flags().StringVar(&cpuProfile, "cpu-profile", "", "Enable CPU profiling.")

View File

@@ -273,50 +273,59 @@ func (r *localRunner) start() {
// all running workers(goroutines) will select on this channel. // all running workers(goroutines) will select on this channel.
// close this channel will stop all running workers. // close this channel will stop all running workers.
quitChan := make(chan bool) quitChan := make(chan bool)
// when this channel is closed, all statistics are reported successfully
reportedChan := make(chan bool)
go r.spawnWorkers(r.spawnCount, r.spawnRate, quitChan, nil) go r.spawnWorkers(r.spawnCount, r.spawnRate, quitChan, nil)
// output setup // output setup
r.outputOnStart() r.outputOnStart()
// start running // start running
var ticker = time.NewTicker(reportStatsInterval) go func() {
for { var ticker = time.NewTicker(reportStatsInterval)
select { for {
// record stats select {
case t := <-r.stats.transactionChan: // record stats
r.stats.logTransaction(t.name, t.success, t.elapsedTime, t.contentSize) case t := <-r.stats.transactionChan:
case m := <-r.stats.requestSuccessChan: r.stats.logTransaction(t.name, t.success, t.elapsedTime, t.contentSize)
r.stats.logRequest(m.requestType, m.name, m.responseTime, m.responseLength) case m := <-r.stats.requestSuccessChan:
case n := <-r.stats.requestFailureChan: r.stats.logRequest(m.requestType, m.name, m.responseTime, m.responseLength)
r.stats.logRequest(n.requestType, n.name, n.responseTime, 0) case n := <-r.stats.requestFailureChan:
r.stats.logError(n.requestType, n.name, n.errMsg) r.stats.logRequest(n.requestType, n.name, n.responseTime, 0)
// report stats r.stats.logError(n.requestType, n.name, n.errMsg)
case <-ticker.C: // report stats
r.reportStats() case <-ticker.C:
// stop r.reportStats()
case <-r.stopChan: // close reportedChan and return if the last stats is reported successfully
atomic.StoreInt32(&r.state, stateQuitting) if atomic.LoadInt32(&r.state) == stateQuitting {
close(reportedChan)
// stop previous goroutines without blocking return
// those goroutines will exit when r.safeRun returns }
close(quitChan)
// stop rate limiter
if r.rateLimitEnabled {
r.rateLimiter.Stop()
} }
// report last stats
<-ticker.C
r.reportStats()
// output teardown
r.outputOnStop()
atomic.StoreInt32(&r.state, stateStopped)
return
} }
}()
// stop
<-r.stopChan
atomic.StoreInt32(&r.state, stateQuitting)
// stop previous goroutines without blocking
// those goroutines will exit when r.safeRun returns
close(quitChan)
// wait until all stats are reported successfully
<-reportedChan
// stop rate limiter
if r.rateLimitEnabled {
r.rateLimiter.Stop()
} }
// output teardown
r.outputOnStop()
atomic.StoreInt32(&r.state, stateStopped)
return
} }
func (r *localRunner) stop() { func (r *localRunner) stop() {