TUN-5285: Fallback to HTTP2 immediately if connection times out with no network activity
This commit is contained in:
parent
36479ef11f
commit
0146a8d8ed
|
@ -49,12 +49,12 @@ func NewQUICConnection(
|
||||||
) (*QUICConnection, error) {
|
) (*QUICConnection, error) {
|
||||||
session, err := quic.DialAddr(edgeAddr.String(), tlsConfig, quicConfig)
|
session, err := quic.DialAddr(edgeAddr.String(), tlsConfig, quicConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to dial to edge")
|
return nil, fmt.Errorf("failed to dial to edge: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
registrationStream, err := session.OpenStream()
|
registrationStream, err := session.OpenStream()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to open a registration stream")
|
return nil, fmt.Errorf("failed to open a registration stream: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = controlStreamHandler.ServeControlStream(ctx, registrationStream, connOptions, false)
|
err = controlStreamHandler.ServeControlStream(ctx, registrationStream, connOptions, false)
|
||||||
|
@ -82,7 +82,7 @@ func (q *QUICConnection) Serve(ctx context.Context) error {
|
||||||
if errors.Is(err, context.Canceled) {
|
if errors.Is(err, context.Canceled) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.Wrap(err, "failed to accept QUIC stream")
|
return fmt.Errorf("failed to accept QUIC stream: %w", err)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
defer stream.Close()
|
defer stream.Close()
|
||||||
|
|
|
@ -190,7 +190,13 @@ func ServeTunnelLoop(
|
||||||
case <-gracefulShutdownC:
|
case <-gracefulShutdownC:
|
||||||
return nil
|
return nil
|
||||||
case <-protocolFallback.BackoffTimer():
|
case <-protocolFallback.BackoffTimer():
|
||||||
if !selectNextProtocol(&connLog, protocolFallback, config.ProtocolSelector) {
|
var idleTimeoutError *quic.IdleTimeoutError
|
||||||
|
if !selectNextProtocol(
|
||||||
|
&connLog,
|
||||||
|
protocolFallback,
|
||||||
|
config.ProtocolSelector,
|
||||||
|
errors.As(err, &idleTimeoutError),
|
||||||
|
) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,8 +228,9 @@ func selectNextProtocol(
|
||||||
connLog *zerolog.Logger,
|
connLog *zerolog.Logger,
|
||||||
protocolBackoff *protocolFallback,
|
protocolBackoff *protocolFallback,
|
||||||
selector connection.ProtocolSelector,
|
selector connection.ProtocolSelector,
|
||||||
|
isNetworkActivityTimeout bool,
|
||||||
) bool {
|
) bool {
|
||||||
if protocolBackoff.ReachedMaxRetries() {
|
if protocolBackoff.ReachedMaxRetries() || isNetworkActivityTimeout {
|
||||||
fallback, hasFallback := selector.Fallback()
|
fallback, hasFallback := selector.Fallback()
|
||||||
if !hasFallback {
|
if !hasFallback {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -62,7 +62,7 @@ func TestWaitForBackoffFallback(t *testing.T) {
|
||||||
// Retry #0 and #1. At retry #2, we switch protocol, so the fallback loop has one more retry than this
|
// Retry #0 and #1. At retry #2, we switch protocol, so the fallback loop has one more retry than this
|
||||||
for i := 0; i < int(maxRetries-1); i++ {
|
for i := 0; i < int(maxRetries-1); i++ {
|
||||||
protocolFallback.BackoffTimer() // simulate retry
|
protocolFallback.BackoffTimer() // simulate retry
|
||||||
ok := selectNextProtocol(&log, protocolFallback, protocolSelector)
|
ok := selectNextProtocol(&log, protocolFallback, protocolSelector, false)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equal(t, initProtocol, protocolFallback.protocol)
|
assert.Equal(t, initProtocol, protocolFallback.protocol)
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ func TestWaitForBackoffFallback(t *testing.T) {
|
||||||
// Retry fallback protocol
|
// Retry fallback protocol
|
||||||
for i := 0; i < int(maxRetries); i++ {
|
for i := 0; i < int(maxRetries); i++ {
|
||||||
protocolFallback.BackoffTimer() // simulate retry
|
protocolFallback.BackoffTimer() // simulate retry
|
||||||
ok := selectNextProtocol(&log, protocolFallback, protocolSelector)
|
ok := selectNextProtocol(&log, protocolFallback, protocolSelector, false)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
fallback, ok := protocolSelector.Fallback()
|
fallback, ok := protocolSelector.Fallback()
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
|
@ -82,12 +82,19 @@ func TestWaitForBackoffFallback(t *testing.T) {
|
||||||
|
|
||||||
// No protocol to fallback, return error
|
// No protocol to fallback, return error
|
||||||
protocolFallback.BackoffTimer() // simulate retry
|
protocolFallback.BackoffTimer() // simulate retry
|
||||||
ok := selectNextProtocol(&log, protocolFallback, protocolSelector)
|
ok := selectNextProtocol(&log, protocolFallback, protocolSelector, false)
|
||||||
assert.False(t, ok)
|
assert.False(t, ok)
|
||||||
|
|
||||||
protocolFallback.reset()
|
protocolFallback.reset()
|
||||||
protocolFallback.BackoffTimer() // simulate retry
|
protocolFallback.BackoffTimer() // simulate retry
|
||||||
ok = selectNextProtocol(&log, protocolFallback, protocolSelector)
|
ok = selectNextProtocol(&log, protocolFallback, protocolSelector, false)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equal(t, initProtocol, protocolFallback.protocol)
|
assert.Equal(t, initProtocol, protocolFallback.protocol)
|
||||||
|
|
||||||
|
protocolFallback.reset()
|
||||||
|
protocolFallback.BackoffTimer() // simulate retry
|
||||||
|
ok = selectNextProtocol(&log, protocolFallback, protocolSelector, true)
|
||||||
|
// Check that we get a true after the first try itself when this flag is true. This allows us to immediately
|
||||||
|
// switch protocols.
|
||||||
|
assert.True(t, ok)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue