health.go
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 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
		}
	}
}
// 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.