From 3d4198ac4291e31be9f91e662f8ed057c8d331ae Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Tue, 7 Oct 2025 00:07:25 +0300 Subject: [PATCH] remove goroutine for db Signed-off-by: Vasiliy Tolstov --- hooks/sql/stats.go | 100 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 23 deletions(-) diff --git a/hooks/sql/stats.go b/hooks/sql/stats.go index b0f086f6..4d36ed44 100644 --- a/hooks/sql/stats.go +++ b/hooks/sql/stats.go @@ -3,6 +3,7 @@ package sql import ( "context" "database/sql" + "sync" "time" ) @@ -11,31 +12,84 @@ type Statser interface { } func NewStatsMeter(ctx context.Context, db Statser, opts ...Option) { + if db == nil { + return + } + options := NewOptions(opts...) - go func() { - ticker := time.NewTicker(options.MeterStatsInterval) - defer ticker.Stop() + var ( + statsMu sync.Mutex + lastUpdated time.Time + maxOpenConnections, openConnections, inUse, idle, waitCount float64 + maxIdleClosed, maxIdleTimeClosed, maxLifetimeClosed float64 + waitDuration float64 + ) - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - if db == nil { - return - } - stats := db.Stats() - options.Meter.Counter(MaxOpenConnections).Set(uint64(stats.MaxOpenConnections)) - options.Meter.Counter(OpenConnections).Set(uint64(stats.OpenConnections)) - options.Meter.Counter(InuseConnections).Set(uint64(stats.InUse)) - options.Meter.Counter(IdleConnections).Set(uint64(stats.Idle)) - options.Meter.Counter(WaitConnections).Set(uint64(stats.WaitCount)) - options.Meter.FloatCounter(BlockedSeconds).Set(stats.WaitDuration.Seconds()) - options.Meter.Counter(MaxIdleClosed).Set(uint64(stats.MaxIdleClosed)) - options.Meter.Counter(MaxIdletimeClosed).Set(uint64(stats.MaxIdleTimeClosed)) - options.Meter.Counter(MaxLifetimeClosed).Set(uint64(stats.MaxLifetimeClosed)) - } + updateFn := func() { + statsMu.Lock() + defer statsMu.Unlock() + + if time.Since(lastUpdated) < options.MeterStatsInterval { + return } - }() + + stats := db.Stats() + maxOpenConnections = float64(stats.MaxOpenConnections) + openConnections = float64(stats.OpenConnections) + inUse = float64(stats.InUse) + idle = float64(stats.Idle) + waitCount = float64(stats.WaitCount) + maxIdleClosed = float64(stats.MaxIdleClosed) + maxIdleTimeClosed = float64(stats.MaxIdleTimeClosed) + maxLifetimeClosed = float64(stats.MaxLifetimeClosed) + waitDuration = float64(stats.WaitDuration.Seconds()) + + lastUpdated = time.Now() + } + + options.Meter.Gauge(MaxOpenConnections, func() float64 { + updateFn() + return maxOpenConnections + }) + + options.Meter.Gauge(OpenConnections, func() float64 { + updateFn() + return openConnections + }) + + options.Meter.Gauge(InuseConnections, func() float64 { + updateFn() + return inUse + }) + + options.Meter.Gauge(IdleConnections, func() float64 { + updateFn() + return idle + }) + + options.Meter.Gauge(WaitConnections, func() float64 { + updateFn() + return waitCount + }) + + options.Meter.Gauge(BlockedSeconds, func() float64 { + updateFn() + return waitDuration + }) + + options.Meter.Gauge(MaxIdleClosed, func() float64 { + updateFn() + return maxIdleClosed + }) + + options.Meter.Gauge(MaxIdletimeClosed, func() float64 { + updateFn() + return maxIdleTimeClosed + }) + + options.Meter.Gauge(MaxLifetimeClosed, func() float64 { + updateFn() + return maxLifetimeClosed + }) }