Skip to content

Commit a9709c3

Browse files
authored
Added logs for reasons causing connection and transport close (#5840)
1 parent aba03e1 commit a9709c3

File tree

8 files changed

+71
-79
lines changed

8 files changed

+71
-79
lines changed

clientconn.go

+3
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,9 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne
12741274

12751275
newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, addr, copts, onGoAway, onClose)
12761276
if err != nil {
1277+
if logger.V(2) {
1278+
logger.Infof("Creating new client transport to %q: %v", addr, err)
1279+
}
12771280
// newTr is either nil, or closed.
12781281
hcancel()
12791282
channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %s. Err: %v", addr, err)

internal/transport/controlbuf.go

+7-21
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ type goAway struct {
191191
code http2.ErrCode
192192
debugData []byte
193193
headsUp bool
194-
closeConn bool
194+
closeConn error // if set, loopyWriter will exit, resulting in conn closure
195195
}
196196

197197
func (*goAway) isTransportResponseFrame() bool { return false }
@@ -416,7 +416,7 @@ func (c *controlBuffer) get(block bool) (interface{}, error) {
416416
select {
417417
case <-c.ch:
418418
case <-c.done:
419-
return nil, ErrConnClosing
419+
return nil, errors.New("transport closed by client")
420420
}
421421
}
422422
}
@@ -527,18 +527,6 @@ const minBatchSize = 1000
527527
// As an optimization, to increase the batch size for each flush, loopy yields the processor, once
528528
// if the batch size is too low to give stream goroutines a chance to fill it up.
529529
func (l *loopyWriter) run() (err error) {
530-
defer func() {
531-
if err == ErrConnClosing {
532-
// Don't log ErrConnClosing as error since it happens
533-
// 1. When the connection is closed by some other known issue.
534-
// 2. User closed the connection.
535-
// 3. A graceful close of connection.
536-
if logger.V(logLevel) {
537-
logger.Infof("transport: loopyWriter.run returning. %v", err)
538-
}
539-
err = nil
540-
}
541-
}()
542530
for {
543531
it, err := l.cbuf.get(true)
544532
if err != nil {
@@ -582,7 +570,6 @@ func (l *loopyWriter) run() (err error) {
582570
}
583571
l.framer.writer.Flush()
584572
break hasdata
585-
586573
}
587574
}
588575
}
@@ -670,11 +657,10 @@ func (l *loopyWriter) headerHandler(h *headerFrame) error {
670657
func (l *loopyWriter) originateStream(str *outStream) error {
671658
hdr := str.itl.dequeue().(*headerFrame)
672659
if err := hdr.initStream(str.id); err != nil {
673-
if err == ErrConnClosing {
674-
return err
660+
if err == errStreamDrain { // errStreamDrain need not close transport
661+
return nil
675662
}
676-
// Other errors(errStreamDrain) need not close transport.
677-
return nil
663+
return err
678664
}
679665
if err := l.writeHeader(str.id, hdr.endStream, hdr.hf, hdr.onWrite); err != nil {
680666
return err
@@ -772,7 +758,7 @@ func (l *loopyWriter) cleanupStreamHandler(c *cleanupStream) error {
772758
}
773759
}
774760
if l.side == clientSide && l.draining && len(l.estdStreams) == 0 {
775-
return ErrConnClosing
761+
return errors.New("finished processing active streams while in draining mode")
776762
}
777763
return nil
778764
}
@@ -807,7 +793,7 @@ func (l *loopyWriter) incomingGoAwayHandler(*incomingGoAway) error {
807793
if l.side == clientSide {
808794
l.draining = true
809795
if len(l.estdStreams) == 0 {
810-
return ErrConnClosing
796+
return errors.New("received GOAWAY with no active streams")
811797
}
812798
}
813799
return nil

internal/transport/handler_server.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,15 @@ type serverHandlerTransport struct {
141141
stats []stats.Handler
142142
}
143143

144-
func (ht *serverHandlerTransport) Close() {
145-
ht.closeOnce.Do(ht.closeCloseChanOnce)
144+
func (ht *serverHandlerTransport) Close(err error) {
145+
ht.closeOnce.Do(func() {
146+
if logger.V(logLevel) {
147+
logger.Infof("Closing serverHandlerTransport: %v", err)
148+
}
149+
close(ht.closedCh)
150+
})
146151
}
147152

148-
func (ht *serverHandlerTransport) closeCloseChanOnce() { close(ht.closedCh) }
149-
150153
func (ht *serverHandlerTransport) RemoteAddr() net.Addr { return strAddr(ht.req.RemoteAddr) }
151154

152155
// strAddr is a net.Addr backed by either a TCP "ip:port" string, or
@@ -236,7 +239,7 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro
236239
})
237240
}
238241
}
239-
ht.Close()
242+
ht.Close(errors.New("finished writing status"))
240243
return err
241244
}
242245

@@ -346,7 +349,7 @@ func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), trace
346349
case <-ht.req.Context().Done():
347350
}
348351
cancel()
349-
ht.Close()
352+
ht.Close(errors.New("request is done processing"))
350353
}()
351354

352355
req := ht.req

internal/transport/http2_client.go

+13-6
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,11 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
242242
go func(conn net.Conn) {
243243
defer ctxMonitorDone.Fire() // Signal this goroutine has exited.
244244
<-newClientCtx.Done() // Block until connectCtx expires or the defer above executes.
245-
if connectCtx.Err() != nil {
245+
if err := connectCtx.Err(); err != nil {
246246
// connectCtx expired before exiting the function. Hard close the connection.
247+
if logger.V(logLevel) {
248+
logger.Infof("newClientTransport: aborting due to connectCtx: %v", err)
249+
}
247250
conn.Close()
248251
}
249252
}(conn)
@@ -445,10 +448,8 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
445448
go func() {
446449
t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst)
447450
err := t.loopy.run()
448-
if err != nil {
449-
if logger.V(logLevel) {
450-
logger.Errorf("transport: loopyWriter.run returning. Err: %v", err)
451-
}
451+
if logger.V(logLevel) {
452+
logger.Infof("transport: loopyWriter exited. Closing connection. Err: %v", err)
452453
}
453454
// Do not close the transport. Let reader goroutine handle it since
454455
// there might be data in the buffers.
@@ -951,6 +952,9 @@ func (t *http2Client) Close(err error) {
951952
t.mu.Unlock()
952953
return
953954
}
955+
if logger.V(logLevel) {
956+
logger.Infof("transport: closing: %v", err)
957+
}
954958
// Call t.onClose ASAP to prevent the client from attempting to create new
955959
// streams.
956960
t.onClose()
@@ -1003,11 +1007,14 @@ func (t *http2Client) GracefulClose() {
10031007
t.mu.Unlock()
10041008
return
10051009
}
1010+
if logger.V(logLevel) {
1011+
logger.Infof("transport: GracefulClose called")
1012+
}
10061013
t.state = draining
10071014
active := len(t.activeStreams)
10081015
t.mu.Unlock()
10091016
if active == 0 {
1010-
t.Close(ErrConnClosing)
1017+
t.Close(connectionErrorf(true, nil, "no active streams left to process while draining"))
10111018
return
10121019
}
10131020
t.controlBuf.put(&incomingGoAway{})

internal/transport/http2_server.go

+31-38
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package transport
2121
import (
2222
"bytes"
2323
"context"
24+
"errors"
2425
"fmt"
2526
"io"
2627
"math"
@@ -293,7 +294,7 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
293294

294295
defer func() {
295296
if err != nil {
296-
t.Close()
297+
t.Close(err)
297298
}
298299
}()
299300

@@ -331,10 +332,9 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
331332
go func() {
332333
t.loopy = newLoopyWriter(serverSide, t.framer, t.controlBuf, t.bdpEst)
333334
t.loopy.ssGoAwayHandler = t.outgoingGoAwayHandler
334-
if err := t.loopy.run(); err != nil {
335-
if logger.V(logLevel) {
336-
logger.Errorf("transport: loopyWriter.run returning. Err: %v", err)
337-
}
335+
err := t.loopy.run()
336+
if logger.V(logLevel) {
337+
logger.Infof("transport: loopyWriter exited. Closing connection. Err: %v", err)
338338
}
339339
t.conn.Close()
340340
t.controlBuf.finish()
@@ -344,8 +344,9 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
344344
return t, nil
345345
}
346346

347-
// operateHeader takes action on the decoded headers.
348-
func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) (fatal bool) {
347+
// operateHeaders takes action on the decoded headers. Returns an error if fatal
348+
// error encountered and transport needs to close, otherwise returns nil.
349+
func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) error {
349350
// Acquire max stream ID lock for entire duration
350351
t.maxStreamMu.Lock()
351352
defer t.maxStreamMu.Unlock()
@@ -361,15 +362,12 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
361362
rstCode: http2.ErrCodeFrameSize,
362363
onWrite: func() {},
363364
})
364-
return false
365+
return nil
365366
}
366367

367368
if streamID%2 != 1 || streamID <= t.maxStreamID {
368369
// illegal gRPC stream id.
369-
if logger.V(logLevel) {
370-
logger.Errorf("transport: http2Server.HandleStreams received an illegal stream id: %v", streamID)
371-
}
372-
return true
370+
return fmt.Errorf("received an illegal stream id: %v. headers frame: %+v", streamID, frame)
373371
}
374372
t.maxStreamID = streamID
375373

@@ -453,7 +451,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
453451
status: status.New(codes.Internal, errMsg),
454452
rst: !frame.StreamEnded(),
455453
})
456-
return false
454+
return nil
457455
}
458456

459457
if !isGRPC || headerError {
@@ -463,7 +461,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
463461
rstCode: http2.ErrCodeProtocol,
464462
onWrite: func() {},
465463
})
466-
return false
464+
return nil
467465
}
468466

469467
// "If :authority is missing, Host must be renamed to :authority." - A41
@@ -503,7 +501,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
503501
if t.state != reachable {
504502
t.mu.Unlock()
505503
s.cancel()
506-
return false
504+
return nil
507505
}
508506
if uint32(len(t.activeStreams)) >= t.maxStreams {
509507
t.mu.Unlock()
@@ -514,7 +512,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
514512
onWrite: func() {},
515513
})
516514
s.cancel()
517-
return false
515+
return nil
518516
}
519517
if httpMethod != http.MethodPost {
520518
t.mu.Unlock()
@@ -530,7 +528,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
530528
rst: !frame.StreamEnded(),
531529
})
532530
s.cancel()
533-
return false
531+
return nil
534532
}
535533
if t.inTapHandle != nil {
536534
var err error
@@ -550,7 +548,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
550548
status: stat,
551549
rst: !frame.StreamEnded(),
552550
})
553-
return false
551+
return nil
554552
}
555553
}
556554
t.activeStreams[streamID] = s
@@ -597,7 +595,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
597595
wq: s.wq,
598596
})
599597
handle(s)
600-
return false
598+
return nil
601599
}
602600

603601
// HandleStreams receives incoming streams using the given handler. This is
@@ -630,19 +628,16 @@ func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context.
630628
continue
631629
}
632630
if err == io.EOF || err == io.ErrUnexpectedEOF {
633-
t.Close()
631+
t.Close(err)
634632
return
635633
}
636-
if logger.V(logLevel) {
637-
logger.Warningf("transport: http2Server.HandleStreams failed to read frame: %v", err)
638-
}
639-
t.Close()
634+
t.Close(err)
640635
return
641636
}
642637
switch frame := frame.(type) {
643638
case *http2.MetaHeadersFrame:
644-
if t.operateHeaders(frame, handle, traceCtx) {
645-
t.Close()
639+
if err := t.operateHeaders(frame, handle, traceCtx); err != nil {
640+
t.Close(err)
646641
break
647642
}
648643
case *http2.DataFrame:
@@ -886,10 +881,7 @@ func (t *http2Server) handlePing(f *http2.PingFrame) {
886881

887882
if t.pingStrikes > maxPingStrikes {
888883
// Send goaway and close the connection.
889-
if logger.V(logLevel) {
890-
logger.Errorf("transport: Got too many pings from the client, closing the connection.")
891-
}
892-
t.controlBuf.put(&goAway{code: http2.ErrCodeEnhanceYourCalm, debugData: []byte("too_many_pings"), closeConn: true})
884+
t.controlBuf.put(&goAway{code: http2.ErrCodeEnhanceYourCalm, debugData: []byte("too_many_pings"), closeConn: errors.New("got too many pings from the client")})
893885
}
894886
}
895887

@@ -1169,10 +1161,7 @@ func (t *http2Server) keepalive() {
11691161
continue
11701162
}
11711163
if outstandingPing && kpTimeoutLeft <= 0 {
1172-
if logger.V(logLevel) {
1173-
logger.Infof("transport: closing server transport due to idleness.")
1174-
}
1175-
t.Close()
1164+
t.Close(fmt.Errorf("keepalive ping not acked within timeout %s", t.kp.Time))
11761165
return
11771166
}
11781167
if !outstandingPing {
@@ -1199,12 +1188,15 @@ func (t *http2Server) keepalive() {
11991188
// Close starts shutting down the http2Server transport.
12001189
// TODO(zhaoq): Now the destruction is not blocked on any pending streams. This
12011190
// could cause some resource issue. Revisit this later.
1202-
func (t *http2Server) Close() {
1191+
func (t *http2Server) Close(err error) {
12031192
t.mu.Lock()
12041193
if t.state == closing {
12051194
t.mu.Unlock()
12061195
return
12071196
}
1197+
if logger.V(logLevel) {
1198+
logger.Infof("transport: closing: %v", err)
1199+
}
12081200
t.state = closing
12091201
streams := t.activeStreams
12101202
t.activeStreams = nil
@@ -1319,19 +1311,20 @@ func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) {
13191311
// Stop accepting more streams now.
13201312
t.state = draining
13211313
sid := t.maxStreamID
1314+
retErr := g.closeConn
13221315
if len(t.activeStreams) == 0 {
1323-
g.closeConn = true
1316+
retErr = errors.New("second GOAWAY written and no active streams left to process")
13241317
}
13251318
t.mu.Unlock()
13261319
t.maxStreamMu.Unlock()
13271320
if err := t.framer.fr.WriteGoAway(sid, g.code, g.debugData); err != nil {
13281321
return false, err
13291322
}
1330-
if g.closeConn {
1323+
if retErr != nil {
13311324
// Abruptly close the connection following the GoAway (via
13321325
// loopywriter). But flush out what's inside the buffer first.
13331326
t.framer.writer.Flush()
1334-
return false, fmt.Errorf("transport: Connection closing")
1327+
return false, retErr
13351328
}
13361329
return true, nil
13371330
}

internal/transport/transport.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ type ServerTransport interface {
701701
// Close tears down the transport. Once it is called, the transport
702702
// should not be accessed any more. All the pending streams and their
703703
// handlers will be terminated asynchronously.
704-
Close()
704+
Close(err error)
705705

706706
// RemoteAddr returns the remote network address.
707707
RemoteAddr() net.Addr

0 commit comments

Comments
 (0)