@@ -227,6 +227,7 @@ type ClientConn struct {
227
227
br * bufio.Reader
228
228
fr * Framer
229
229
lastActive time.Time
230
+ lastIdle time.Time // time last idle
230
231
// Settings from peer: (also guarded by mu)
231
232
maxFrameSize uint32
232
233
maxConcurrentStreams uint32
@@ -736,7 +737,8 @@ func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) {
736
737
}
737
738
738
739
st .canTakeNewRequest = cc .goAway == nil && ! cc .closed && ! cc .closing && maxConcurrentOkay &&
739
- int64 (cc .nextStreamID )+ 2 * int64 (cc .pendingRequests ) < math .MaxInt32
740
+ int64 (cc .nextStreamID )+ 2 * int64 (cc .pendingRequests ) < math .MaxInt32 &&
741
+ ! cc .tooIdleLocked ()
740
742
st .freshConn = cc .nextStreamID == 1 && st .canTakeNewRequest
741
743
return
742
744
}
@@ -746,6 +748,16 @@ func (cc *ClientConn) canTakeNewRequestLocked() bool {
746
748
return st .canTakeNewRequest
747
749
}
748
750
751
+ // tooIdleLocked reports whether this connection has been been sitting idle
752
+ // for too much wall time.
753
+ func (cc * ClientConn ) tooIdleLocked () bool {
754
+ // The Round(0) strips the monontonic clock reading so the
755
+ // times are compared based on their wall time. We don't want
756
+ // to reuse a connection that's been sitting idle during
757
+ // VM/laptop suspend if monotonic time was also frozen.
758
+ return cc .idleTimeout != 0 && ! cc .lastIdle .IsZero () && time .Since (cc .lastIdle .Round (0 )) > cc .idleTimeout
759
+ }
760
+
749
761
// onIdleTimeout is called from a time.AfterFunc goroutine. It will
750
762
// only be called when we're idle, but because we're coming from a new
751
763
// goroutine, there could be a new request coming in at the same time,
@@ -1150,6 +1162,7 @@ func (cc *ClientConn) awaitOpenSlotForRequest(req *http.Request) error {
1150
1162
}
1151
1163
return errClientConnUnusable
1152
1164
}
1165
+ cc .lastIdle = time.Time {}
1153
1166
if int64 (len (cc .streams ))+ 1 <= int64 (cc .maxConcurrentStreams ) {
1154
1167
if waitingForConn != nil {
1155
1168
close (waitingForConn )
@@ -1638,6 +1651,7 @@ func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream {
1638
1651
delete (cc .streams , id )
1639
1652
if len (cc .streams ) == 0 && cc .idleTimer != nil {
1640
1653
cc .idleTimer .Reset (cc .idleTimeout )
1654
+ cc .lastIdle = time .Now ()
1641
1655
}
1642
1656
close (cs .done )
1643
1657
// Wake up checkResetOrDone via clientStream.awaitFlowControl and
0 commit comments