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