Repository: grpc/grpc-go
File: clientconn.go (Go)

Code before:
	dialDuration := minConnectTimeout
	if ac.dopts.minConnectTimeout != nil {
		dialDuration = ac.dopts.minConnectTimeout()
	}

	if dialDuration < backoffFor {
		// Give dial more time as we keep failing to connect.
		dialDuration = backoffFor
	}
	// We can potentially spend all the time trying the first address, and
	// if the server accepts the connection and then hangs, the following
	// addresses will never be tried.
	//
	// The spec doesn't mention what should be done for multiple addresses.
	// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md#proposed-backoff-algorithm
	connectDeadline := time.Now().Add(dialDuration)

	ac.updateConnectivityState(connectivity.Connecting, nil)
	ac.mu.Unlock()

	if err := ac.tryAllAddrs(acCtx, addrs, connectDeadline); err != nil {
		if !errors.Is(err, context.Canceled) {
			connectionAttemptsFailedMetric.Record(ac.cc.metricsRecorderList, 1, ac.cc.target, ac.backendServiceLabel, ac.localityLabel)
		} else {
			// This records cancelled connection attempts which can be later replaced by a metric.
			channelz.Infof(logger, ac.channelz, "Received context cancelled on subconn, not recording this as a failed connection attempt.")
		}
		// TODO: #7534 - Move re-resolution requests into the pick_first LB policy
		// to ensure one resolution request per pass instead of per subconn failure.
		ac.cc.resolveNow(resolver.ResolveNowOptions{})
		ac.mu.Lock()
		if acCtx.Err() != nil {
			// addrConn was torn down.
			ac.mu.Unlock()
			return
		}
		// After exhausting all addresses, the addrConn enters
		// TRANSIENT_FAILURE.
		ac.updateConnectivityState(connectivity.TransientFailure, err)

		// Backoff.
		b := ac.resetBackoff
		ac.mu.Unlock()

		timer := time.NewTimer(backoffFor)
		select {
		case <-timer.C:
			ac.mu.Lock()
			ac.backoffIdx++
			ac.mu.Unlock()
		case <-b:

Review comment (bug):
Do we really need to add a trace event for this as well? `channelz.Infof` does that. If we just want to log this, then `logger.Infof` should be good enough and we should guard this with `V(2)` check. 

Also, the log message could be improved. How about something like "Context cancellation detected; not recording this as a failed connection attempt."

Code after:
		ac.mu.Unlock()
		return
	}

	addrs := ac.addrs
	backoffFor := ac.dopts.bs.Backoff(ac.backoffIdx)
	// This will be the duration that dial gets to finish.
	dialDuration := minConnectTimeout
	if ac.dopts.minConnectTimeout != nil {
		dialDuration = ac.dopts.minConnectTimeout()
	}

	if dialDuration < backoffFor {
		// Give dial more time as we keep failing to connect.
		dialDuration = backoffFor
	}
	// We can potentially spend all the time trying the first address, and
	// if the server accepts the connection and then hangs, the following
	// addresses will never be tried.
	//
	// The spec doesn't mention what should be done for multiple addresses.
	// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md#proposed-backoff-algorithm
	connectDeadline := time.Now().Add(dialDuration)

	ac.updateConnectivityState(connectivity.Connecting, nil)
	ac.mu.Unlock()

	if err := ac.tryAllAddrs(acCtx, addrs, connectDeadline); err != nil {
		if !errors.Is(err, context.Canceled) {
			connectionAttemptsFailedMetric.Record(ac.cc.metricsRecorderList, 1, ac.cc.target, ac.backendServiceLabel, ac.localityLabel)
		} else {
			if logger.V(2) {
				// This records cancelled connection attempts which can be later
				// replaced by a metric.
				logger.Infof("Context cancellation detected; not recording this as a failed connection attempt.")
			}
		}
		// TODO: #7534 - Move re-resolution requests into the pick_first LB policy
		// to ensure one resolution request per pass instead of per subconn failure.
		ac.cc.resolveNow(resolver.ResolveNowOptions{})
		ac.mu.Lock()
		if acCtx.Err() != nil {
			// addrConn was torn down.
			ac.mu.Unlock()
			return
		}
		// After exhausting all addresses, the addrConn enters
		// TRANSIENT_FAILURE.
		ac.updateConnectivityState(connectivity.TransientFailure, err)

		// Backoff.