Repository: grpc/grpc-go
File: internal/transport/http2_client.go (Go)

Code before:
		rstCode: rstCode,
	}
	addBackStreamQuota := func() bool {
		t.streamQuota++
		if t.streamQuota > 0 && t.waitingStreams > 0 {
			select {
			case t.streamsQuotaAvailable <- struct{}{}:
			default:
			}
		}
		return true
	}
	t.controlBuf.executeAndPut(addBackStreamQuota, cleanup)
	// This will unblock write.
	close(s.done)
	if s.doneFunc != nil {
		s.doneFunc()
	}
}

// Close kicks off the shutdown process of the transport. This should be called
// only once on a transport. Once it is called, the transport should not be
// accessed anymore.
func (t *http2Client) Close(err error) {
	if err := t.conn.SetWriteDeadline(time.Now().Add(time.Second * 10)); err != nil {
		logger.Warningf("Failed to set write deadline when closing connection: %v", err)
	}
	// For background on the deadline value chosen here, see
	// https://github.com/grpc/grpc-go/issues/8425#issuecomment-3057938248 .
	if err := t.conn.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
		logger.Warningf("Failed to set read deadline when closing connection: %v", err)
	}
	t.mu.Lock()
	// Make sure we only close once.
	if t.state == closing {
		t.mu.Unlock()
		return
	}
	if t.logger.V(logLevel) {
		t.logger.Infof("Closing: %v", err)
	}
	// Call t.onClose ASAP to prevent the client from attempting to create new
	// streams.
	if t.state != draining {
		t.onClose(GoAwayInvalid)
	}
	t.state = closing
	streams := t.activeStreams
	t.activeStreams = nil
	if t.kpDormant {
		// If the keepalive goroutine is blocked on this condition variable, we

Review comment (bug):
These logs are too chatty. They're appearing almost every time a connection is closed, e.g:
```
tlogger.go:126: WARNING http2_client.go:993 [transport] Failed to set write deadline when closing connection: set tcp 127.0.0.1:59286: use of closed network connection  (t=+590.186033ms)
```
I don't think we should log here because we are calling `conn.Close` in [another goroutine](https://github.com/grpc/grpc-go/blob/3c743c9d3f630d12ec805055c304cc30fa6ea89d/internal/transport/http2_client.go#L467-L477) and expecting these calls to fail.

Code after:
		rstCode: rstCode,
	}
	addBackStreamQuota := func() bool {
		t.streamQuota++
		if t.streamQuota > 0 && t.waitingStreams > 0 {
			select {
			case t.streamsQuotaAvailable <- struct{}{}:
			default:
			}
		}
		return true
	}
	t.controlBuf.executeAndPut(addBackStreamQuota, cleanup)
	// This will unblock write.
	close(s.done)
	if s.doneFunc != nil {
		s.doneFunc()
	}
}

// Close kicks off the shutdown process of the transport. This should be called
// only once on a transport. Once it is called, the transport should not be
// accessed anymore.
func (t *http2Client) Close(err error) {
	t.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
	// For background on the deadline value chosen here, see
	// https://github.com/grpc/grpc-go/issues/8425#issuecomment-3057938248 .
	t.conn.SetReadDeadline(time.Now().Add(time.Second))
	t.mu.Lock()
	// Make sure we only close once.
	if t.state == closing {
		t.mu.Unlock()
		return
	}
	if t.logger.V(logLevel) {
		t.logger.Infof("Closing: %v", err)
	}
	// Call t.onClose ASAP to prevent the client from attempting to create new
	// streams.
	if t.state != draining {
		t.onClose(GoAwayInvalid)
	}
	t.state = closing
	streams := t.activeStreams
	t.activeStreams = nil
	if t.kpDormant {
		// If the keepalive goroutine is blocked on this condition variable, we
		// should unblock it so that the goroutine eventually exits.
		t.kpDormancyCond.Signal()
	}
	// Append info about previous goaways if there were any, since this may be important