func (c *Connection) healthCheck(connID uint32) {
	defer close(c.healthCheckDone)

	opts := c.opts.HealthChecks

	ticker := c.timeTicker(opts.Interval)
	defer ticker.Stop()

	consecutiveFailures := 0
	for {
		select {
		case <-ticker.C:
		case <-c.healthCheckCtx.Done():
			return
		}

		ctx, cancel := context.WithTimeout(c.healthCheckCtx, opts.Timeout)
		err := c.ping(ctx)
		cancel()
		c.healthCheckHistory.add(err == nil)
		if err == nil {
			if c.log.Enabled(LogLevelDebug) {
				c.log.Debug("Performed successful active health check.")
			}
			consecutiveFailures = 0
			continue
		}

		// If the health check failed because the connection closed or health
		// checks were stopped, we don't need to log or close the connection.
		if GetSystemErrorCode(err) == ErrCodeCancelled || err == ErrInvalidConnectionState {
			c.log.WithFields(ErrField(err)).Debug("Health checker stopped.")
			return
		}

		consecutiveFailures++
		c.log.WithFields(LogFields{
			{"consecutiveFailures", consecutiveFailures},
			ErrField(err),
			{"failuresToClose", opts.FailuresToClose},
		}...).Warn("Failed active health check.")

		if consecutiveFailures >= opts.FailuresToClose {
			c.close(LogFields{
				{"reason", "health check failure"},
				ErrField(err),
			}...)
			return
		}
	}
}
func (c *Connection) healthCheck(connID uint32) {
	defer close(c.healthCheckDone)

	opts := c.opts.HealthChecks

	ticker := c.timeTicker(opts.Interval)
	defer ticker.Stop()

	consecutiveFailures := 0
	for {
		select {
		case <-ticker.C:
		case <-c.healthCheckCtx.Done():
			return
		}

		ctx, cancel := context.WithTimeout(c.healthCheckCtx, opts.Timeout)
		err := c.ping(ctx)
		cancel()
		c.healthCheckHistory.add(err == nil)
		if err == nil {
			if c.log.Enabled(LogLevelDebug) {
				c.log.Debug("Performed successful active health check.")
			}
			consecutiveFailures = 0
			continue
		}

		
		
		if GetSystemErrorCode(err) == ErrCodeCancelled || err == ErrInvalidConnectionState {
			c.log.WithFields(ErrField(err)).Debug("Health checker stopped.")
			return
		}

		consecutiveFailures++
		c.log.WithFields(LogFields{
			{"consecutiveFailures", consecutiveFailures},
			ErrField(err),
			{"failuresToClose", opts.FailuresToClose},
		}...).Warn("Failed active health check.")

		if consecutiveFailures >= opts.FailuresToClose {
			c.close(LogFields{
				{"reason", "health check failure"},
				ErrField(err),
			}...)
			return
		}
	}
}
func ( c * Connection ) healthCheck ( connID uint32 ) { defer close ( c . healthCheckDone ) opts := c . opts . HealthChecks ticker := c . timeTicker ( opts . Interval ) defer ticker . Stop ( ) consecutiveFailures := 0 for { select { case <- ticker . C : case <- c . healthCheckCtx . Done ( ) : return } ctx , cancel := context . WithTimeout ( c . healthCheckCtx , opts . Timeout ) err := c . ping ( ctx ) cancel ( ) c . healthCheckHistory . add ( err == nil ) if err == nil { if c . log . Enabled ( LogLevelDebug ) { c . log . Debug ( " " ) } consecutiveFailures = 0 continue } // If the health check failed because the connection closed or health // checks were stopped, we don't need to log or close the connection. if GetSystemErrorCode ( err ) == ErrCodeCancelled || err == ErrInvalidConnectionState { c . log . WithFields ( ErrField ( err ) ) . Debug ( " " ) return } consecutiveFailures ++ c . log . WithFields ( LogFields { { " " , consecutiveFailures } , ErrField ( err ) , { " " , opts . FailuresToClose } , } ... ) . Warn ( " " ) if consecutiveFailures >= opts . FailuresToClose { c . close ( LogFields { { " " , " " } , ErrField ( err ) , } ... ) return } } }
// healthCheck will do periodic pings on the connection to check the state of the connection.
// We accept connID on the stack so can more easily debug panics or leaked goroutines.
healthCheck will do periodic pings on the connection to check the state of the connection . We accept connID on the stack so can more easily debug panics or leaked goroutines .