p2p/protocols: fix possible metrics loss in AccountingMetrics (#18956)

This commit is contained in:
Janoš Guljaš 2019-01-29 15:19:54 +01:00 committed by Anton Evangelatov
parent a0ac3b6a1a
commit 74c38902ec

View File

@ -36,6 +36,13 @@ type AccountingMetrics struct {
//for a graceful cleanup //for a graceful cleanup
func (am *AccountingMetrics) Close() { func (am *AccountingMetrics) Close() {
close(am.reporter.quit) close(am.reporter.quit)
// wait for reporter loop to finish saving metrics
// before reporter database is closed
select {
case <-time.After(10 * time.Second):
log.Error("accounting metrics reporter timeout")
case <-am.reporter.done:
}
am.reporter.db.Close() am.reporter.db.Close()
} }
@ -46,6 +53,7 @@ type reporter struct {
interval time.Duration //duration at which the reporter will persist metrics interval time.Duration //duration at which the reporter will persist metrics
db *leveldb.DB //the actual DB db *leveldb.DB //the actual DB
quit chan struct{} //quit the reporter loop quit chan struct{} //quit the reporter loop
done chan struct{} //signal that reporter loop is done
} }
//NewMetricsDB creates a new LevelDB instance used to persist metrics defined //NewMetricsDB creates a new LevelDB instance used to persist metrics defined
@ -92,6 +100,7 @@ func NewAccountingMetrics(r metrics.Registry, d time.Duration, path string) *Acc
interval: d, interval: d,
db: db, db: db,
quit: make(chan struct{}), quit: make(chan struct{}),
done: make(chan struct{}),
} }
//run the go routine //run the go routine
@ -106,6 +115,9 @@ func NewAccountingMetrics(r metrics.Registry, d time.Duration, path string) *Acc
//run is the goroutine which periodically sends the metrics to the configured LevelDB //run is the goroutine which periodically sends the metrics to the configured LevelDB
func (r *reporter) run() { func (r *reporter) run() {
// signal that the reporter loop is done
defer close(r.done)
intervalTicker := time.NewTicker(r.interval) intervalTicker := time.NewTicker(r.interval)
for { for {
@ -121,6 +133,9 @@ func (r *reporter) run() {
} }
case <-r.quit: case <-r.quit:
//graceful shutdown //graceful shutdown
if err := r.save(); err != nil {
log.Error("unable to send metrics to LevelDB", "err", err)
}
return return
} }
} }