@@ -865,36 +865,53 @@ func (p *ConnPool) Close() error {
865865}
866866
867867func (p * ConnPool ) isHealthyConn (cn * Conn , now time.Time ) bool {
868- // slight optimization, check expiresAt first.
869- if cn .expiresAt .Before (now ) {
870- return false
868+ // Performance optimization: check conditions from cheapest to most expensive,
869+ // and from most likely to fail to least likely to fail.
870+
871+ // Only fails if ConnMaxLifetime is set AND connection is old.
872+ // Most pools don't set ConnMaxLifetime, so this rarely fails.
873+ if p .cfg .ConnMaxLifetime > 0 {
874+ if cn .expiresAt .Before (now ) {
875+ return false // Connection has exceeded max lifetime
876+ }
871877 }
872878
873- // Check if connection has exceeded idle timeout
874- if p .cfg .ConnMaxIdleTime > 0 && now .Sub (cn .UsedAt ()) >= p .cfg .ConnMaxIdleTime {
875- return false
879+ // Most pools set ConnMaxIdleTime, and idle connections are common.
880+ // Checking this first allows us to fail fast without expensive syscalls.
881+ if p .cfg .ConnMaxIdleTime > 0 {
882+ if now .Sub (cn .UsedAt ()) >= p .cfg .ConnMaxIdleTime {
883+ return false // Connection has been idle too long
884+ }
876885 }
877886
878- cn .SetUsedAt (now )
879- // Check basic connection health
880- // Use GetNetConn() to safely access netConn and avoid data races
887+ // Only run this if the cheap checks passed.
881888 if err := connCheck (cn .getNetConn ()); err != nil {
882889 // If there's unexpected data, it might be push notifications (RESP3)
883- // However, push notification processing is now handled by the client
884- // before WithReader to ensure proper context is available to handlers
885890 if p .cfg .PushNotificationsEnabled && err == errUnexpectedRead {
886- // we know that there is something in the buffer, so peek at the next reply type without
887- // the potential to block
891+ // Peek at the reply type to check if it's a push notification
888892 if replyType , err := cn .rd .PeekReplyType (); err == nil && replyType == proto .RespPush {
889893 // For RESP3 connections with push notifications, we allow some buffered data
890894 // The client will process these notifications before using the connection
891- internal .Logger .Printf (context .Background (), "push: conn[%d] has buffered data, likely push notifications - will be processed by client" , cn .GetID ())
892- return true // Connection is healthy, client will handle notifications
895+ internal .Logger .Printf (
896+ context .Background (),
897+ "push: conn[%d] has buffered data, likely push notifications - will be processed by client" ,
898+ cn .GetID (),
899+ )
900+
901+ // Update timestamp for healthy connection
902+ cn .SetUsedAt (now )
903+
904+ // Connection is healthy, client will handle notifications
905+ return true
893906 }
894- return false // Unexpected data, not push notifications, connection is unhealthy
895- } else {
907+ // Not a push notification - treat as unhealthy
896908 return false
897909 }
910+ // Connection failed health check
911+ return false
898912 }
913+
914+ // Only update UsedAt if connection is healthy (avoids unnecessary atomic store)
915+ cn .SetUsedAt (now )
899916 return true
900917}
0 commit comments