mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-20 06:28:13 +00:00
fix(memory, connection): two data-race/counter defects
1) connection_pool.go: GetConnectionStats read lastRecoveryAttempt (a multi-word time.Time) without any lock while checkAndRecover wrote it under recoveryMutex -> data race on live admin API endpoints. Snapshot it under recoveryMutex (the writer's lock). Regression test TestGetConnectionStatsRace drives the read path concurrent with the locked write under -race. 2) cache/memory memory.go: Cache.Get expired path used an unconditional Delete + atomic decrement, so concurrent Gets on the same expired entry each decremented entryCount/memoryUsage -> permanent negative drift. Use LoadAndDelete-with-guard (as evictOldest/evictToFreeMemory already do) so only the goroutine that actually removes the entry decrements. Regression test TestMemoryCacheConcurrentGetOnExpiredEntry_CountersConsistent.
This commit is contained in:
+7
-1
@@ -259,11 +259,17 @@ func (cpm *ConnectionPoolManager) RecordConnectionFailure() {
|
||||
|
||||
// GetConnectionStats returns current connection statistics
|
||||
func (cpm *ConnectionPoolManager) GetConnectionStats() map[string]any {
|
||||
// lastRecoveryAttempt is written by checkAndRecover under recoveryMutex
|
||||
// (time.Time is not atomic), so snapshot it under the same lock.
|
||||
cpm.recoveryMutex.Lock()
|
||||
lastRecovery := cpm.lastRecoveryAttempt
|
||||
cpm.recoveryMutex.Unlock()
|
||||
|
||||
return map[string]any{
|
||||
"active_connections": cpm.activeConnections.Load(),
|
||||
"total_connections": cpm.totalConnections.Load(),
|
||||
"connection_failures": cpm.connectionFailures.Load(),
|
||||
"last_recovery_attempt": cpm.lastRecoveryAttempt,
|
||||
"last_recovery_attempt": lastRecovery,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user