MCPcopy
hub / github.com/grpc/grpc-go / keepalive

Method keepalive

internal/transport/http2_client.go:1764–1847  ·  view source on GitHub ↗

keepalive running in a separate goroutine makes sure the connection is alive by sending pings.

()

Source from the content-addressed store, hash-verified

1762
1763// keepalive running in a separate goroutine makes sure the connection is alive by sending pings.
1764func (t *http2Client) keepalive() {
1765 var err error
1766 defer func() {
1767 close(t.keepaliveDone)
1768 if err != nil {
1769 t.Close(err)
1770 }
1771 }()
1772 p := &ping{data: [8]byte{}}
1773 // True iff a ping has been sent, and no data has been received since then.
1774 outstandingPing := false
1775 // Amount of time remaining before which we should receive an ACK for the
1776 // last sent ping.
1777 timeoutLeft := time.Duration(0)
1778 // Records the last value of t.lastRead before we go block on the timer.
1779 // This is required to check for read activity since then.
1780 prevNano := time.Now().UnixNano()
1781 timer := time.NewTimer(t.kp.Time)
1782 for {
1783 select {
1784 case <-timer.C:
1785 lastRead := atomic.LoadInt64(&t.lastRead)
1786 if lastRead > prevNano {
1787 // There has been read activity since the last time we were here.
1788 outstandingPing = false
1789 // Next timer should fire at kp.Time seconds from lastRead time.
1790 timer.Reset(time.Duration(lastRead) + t.kp.Time - time.Duration(time.Now().UnixNano()))
1791 prevNano = lastRead
1792 continue
1793 }
1794 if outstandingPing && timeoutLeft <= 0 {
1795 err = connectionErrorf(true, nil, "keepalive ping failed to receive ACK within timeout")
1796 return
1797 }
1798 t.mu.Lock()
1799 if t.state == closing {
1800 // If the transport is closing, we should exit from the
1801 // keepalive goroutine here. If not, we could have a race
1802 // between the call to Signal() from Close() and the call to
1803 // Wait() here, whereby the keepalive goroutine ends up
1804 // blocking on the condition variable which will never be
1805 // signalled again.
1806 t.mu.Unlock()
1807 return
1808 }
1809 if len(t.activeStreams) < 1 && !t.kp.PermitWithoutStream {
1810 // If a ping was sent out previously (because there were active
1811 // streams at that point) which wasn't acked and its timeout
1812 // hadn't fired, but we got here and are about to go dormant,
1813 // we should make sure that we unconditionally send a ping once
1814 // we awaken.
1815 outstandingPing = false
1816 t.kpDormant = true
1817 t.kpDormancyCond.Wait()
1818 }
1819 t.kpDormant = false
1820 t.mu.Unlock()
1821

Callers 1

NewHTTP2ClientFunction · 0.95

Calls 13

CloseMethod · 0.95
ResetMethod · 0.95
StopMethod · 0.95
IsOnFunction · 0.92
connectionErrorfFunction · 0.85
NowMethod · 0.80
NewTimerMethod · 0.80
WaitMethod · 0.80
AddMethod · 0.65
LockMethod · 0.45
UnlockMethod · 0.45
putMethod · 0.45

Tested by

no test coverage detected