@@ -108,23 +108,17 @@ type Transport struct {
108
108
// waiting for their turn.
109
109
StrictMaxConcurrentStreams bool
110
110
111
- // PingPeriod controls how often pings are sent on idle connections to
112
- // check the liveness of the connection. The connection will be closed
113
- // if response is not received within PingTimeout.
114
- // 0 means no periodic pings. Defaults to 0.
115
- PingPeriod time.Duration
116
-
117
111
// PingTimeout is the timeout after which the connection will be closed
118
112
// if a response to Ping is not received.
119
- // Defaults to PingPeriod/2
113
+ // Defaults to 1s.
120
114
PingTimeout time.Duration
121
115
122
- // ReadIdleTimeout is the timeout after which the periodic ping for
123
- // connection health check will begin if no frame is received on the
124
- // connection.
125
- // The health check will stop once there is a frame received on the
126
- // connection .
127
- // Defaults to 60s .
116
+ // ReadIdleTimeout is the timeout after which a health check using ping
117
+ // frame will be carried out if no frame is received on the connection.
118
+ // Note that a ping response will is considered a received frame, so if
119
+ // there is no other traffic on the connection, the health check will
120
+ // be performed every ReadIdleTimeout interval .
121
+ // Default to 0, which means no health check .
128
122
ReadIdleTimeout time.Duration
129
123
130
124
// t1, if non-nil, is the standard library Transport using
@@ -160,7 +154,7 @@ func (t *Transport) readIdleTimeout() time.Duration {
160
154
161
155
func (t * Transport ) pingTimeout () time.Duration {
162
156
if t .PingTimeout == 0 {
163
- return t . PingPeriod / 2
157
+ return 1 * time . Second
164
158
}
165
159
return t .PingTimeout
166
160
@@ -274,9 +268,6 @@ type ClientConn struct {
274
268
275
269
wmu sync.Mutex // held while writing; acquire AFTER mu if holding both
276
270
werr error // first write error that has occurred
277
-
278
- hmu sync.Mutex // guard the healthCheckStopCh
279
- healthCheckStopCh chan struct {} // A close-only channel to stop the health check.
280
271
}
281
272
282
273
// clientStream is the state for a single HTTP/2 stream. One of these
@@ -712,51 +703,18 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
712
703
return cc , nil
713
704
}
714
705
715
- func (cc * ClientConn ) healthCheck (stop chan struct {}) {
716
- pingPeriod := cc .t .PingPeriod
706
+ func (cc * ClientConn ) healthCheck () {
717
707
pingTimeout := cc .t .pingTimeout ()
718
- if pingPeriod == 0 || pingTimeout == 0 {
719
- return
720
- }
721
- ticker := time .NewTicker (pingPeriod )
722
- defer ticker .Stop ()
723
- for {
724
- select {
725
- case <- stop :
726
- return
727
- case <- ticker .C :
728
- ctx , cancel := context .WithTimeout (context .Background (), pingTimeout )
729
- err := cc .Ping (ctx )
730
- cancel ()
731
- if err != nil {
732
- cc .closeForLostPing ()
733
- cc .t .connPool ().MarkDead (cc )
734
- return
735
- }
736
- }
737
- }
738
- }
739
-
740
- func (cc * ClientConn ) startHealthCheck () {
741
- cc .hmu .Lock ()
742
- defer cc .hmu .Unlock ()
743
- if cc .healthCheckStopCh != nil {
744
- // a health check is already running
745
- return
746
- }
747
- cc .healthCheckStopCh = make (chan struct {})
748
- go cc .healthCheck (cc .healthCheckStopCh )
749
- }
750
-
751
- func (cc * ClientConn ) stopHealthCheck () {
752
- cc .hmu .Lock ()
753
- defer cc .hmu .Unlock ()
754
- if cc .healthCheckStopCh == nil {
755
- // no health check running
708
+ // We don't need to periodically ping in the health check, because the readLoop of ClientConn will
709
+ // trigger the healthCheck again if there is no frame received.
710
+ ctx , cancel := context .WithTimeout (context .Background (), pingTimeout )
711
+ err := cc .Ping (ctx )
712
+ cancel ()
713
+ if err != nil {
714
+ cc .closeForLostPing ()
715
+ cc .t .connPool ().MarkDead (cc )
756
716
return
757
717
}
758
- close (cc .healthCheckStopCh )
759
- cc .healthCheckStopCh = nil
760
718
}
761
719
762
720
func (cc * ClientConn ) setGoAway (f * GoAwayFrame ) {
@@ -1804,11 +1762,15 @@ func (rl *clientConnReadLoop) run() error {
1804
1762
gotReply := false // ever saw a HEADERS reply
1805
1763
gotSettings := false
1806
1764
to := cc .t .readIdleTimeout ()
1807
- t := time .AfterFunc (to , cc .startHealthCheck )
1765
+ var t * time.Timer
1766
+ if to != 0 {
1767
+ t = time .AfterFunc (to , cc .healthCheck )
1768
+ }
1808
1769
for {
1809
1770
f , err := cc .fr .ReadFrame ()
1810
- t .Reset (to )
1811
- cc .stopHealthCheck ()
1771
+ if to != 0 {
1772
+ t .Reset (to )
1773
+ }
1812
1774
if err != nil {
1813
1775
cc .vlogf ("http2: Transport readFrame error on conn %p: (%T) %v" , cc , err , err )
1814
1776
}
0 commit comments