protected static void markChannelBrokenAndLogInfoIfHttpClientCodecStateIsNotZero(Channel ch, String callContextForLogs) { HttpClientCodec currentCodec = (HttpClientCodec) ch.pipeline().get(HTTP_CLIENT_CODEC_HANDLER_NAME); if (currentCodec != null) { int currentHttpClientCodecInboundState = determineHttpClientCodecInboundState(currentCodec); if (currentHttpClientCodecInboundState != 0) { boolean channelAlreadyBroken = channelIsMarkedAsBeingBroken(ch); logger.warn( "HttpClientCodec inbound state was not 0. The channel will be marked as broken so it won't be " + "used. bad_httpclientcodec_inbound_state={}, channel_already_broken={}, channel_id={}, " + "call_context=\"{}\"", currentHttpClientCodecInboundState, channelAlreadyBroken, ch.toString(), callContextForLogs ); markChannelAsBroken(ch); } else { int currentHttpClientCodecOutboundState = determineHttpClientCodecOutboundState(currentCodec); if (currentHttpClientCodecOutboundState != 0) { boolean channelAlreadyBroken = channelIsMarkedAsBeingBroken(ch); logger.warn( "HttpClientCodec outbound state was not 0. The channel will be marked as broken so it won't be " + "used. bad_httpclientcodec_outbound_state={}, channel_already_broken={}, channel_id={}, " + "call_context=\"{}\"", currentHttpClientCodecOutboundState, channelAlreadyBroken, ch.toString(), callContextForLogs ); markChannelAsBroken(ch); } } } }
/** * Returns the name that should be used for the span surrounding the downstream call. Defaults to whatever {@link * ProxyRouterSpanNamingAndTaggingStrategy#getInitialSpanName(Object)} returns, with a fallback * of {@link HttpRequestTracingUtils#getFallbackSpanNameForHttpRequest(String, String)} if the naming strategy * returned null or blank string. * * @param downstreamRequest The Netty {@link HttpRequest} for the downstream call. * @param namingStrategy The {@link ProxyRouterSpanNamingAndTaggingStrategy} being used. * @return The name that should be used for the span surrounding the downstream call. */ protected @NotNull String getSubspanSpanName( @NotNull HttpRequest downstreamRequest, @NotNull ProxyRouterSpanNamingAndTaggingStrategy<Span> namingStrategy ) { String spanNameFromStrategy = namingStrategy.getInitialSpanName(downstreamRequest); if (StringUtils.isNotBlank(spanNameFromStrategy)) { return spanNameFromStrategy; } // The naming strategy didn't have anything for us. Fall back to something reasonable. return getFallbackSpanName(downstreamRequest); }
protected ChannelPool getPooledChannelFuture(String downstreamHost, int downstreamPort) { return getPoolMap().get( resolveHostnameToInetSocketAddressWithMultiIpSupport(downstreamHost, downstreamPort) ); }
markChannelAsBroken(ch); releaseChannelBackToPoolIfCallIsActive( ch, pool, callActiveHolder, "error received in downstream pipeline: " + cause.toString(), distributedSpanStackToUse, mdcContextToUse addOrReplacePipelineHandler( new DownstreamIdleChannelTimeoutHandler( downstreamCallTimeoutMillis, () -> callActiveHolder.heldObject, true, if (pipelineContainsHttpClientCodec) { HttpClientCodec currentCodec = (HttpClientCodec) p.get(HTTP_CLIENT_CODEC_HANDLER_NAME); int currentHttpClientCodecInboundState = determineHttpClientCodecInboundState(currentCodec); if (currentHttpClientCodecInboundState != 0) { runnableWithTracingAndMdc( int currentHttpClientCodecOutboundState = determineHttpClientCodecOutboundState(currentCodec); if (currentHttpClientCodecOutboundState != 0) { runnableWithTracingAndMdc( addOrReplacePipelineHandler( new HttpClientCodec(4096, 8192, 8192, true), HTTP_CLIENT_CODEC_HANDLER_NAME, p, registeredHandlerNames ); addOrReplacePipelineHandler(chunkSenderHandler, CHUNK_SENDER_HANDLER_NAME, p, registeredHandlerNames); addOrReplacePipelineHandler(errorHandler, ERROR_HANDLER_NAME, p, registeredHandlerNames);
@DataProvider(value = { "80 | false | localhost | localhost", "80 | true | localhost | localhost:80", "8080 | false | localhost | localhost:8080", "443 | true | localhost | localhost", "443 | false | localhost | localhost:443", "8080 | true | localhost | localhost:8080", }, splitBy = "\\|") @Test public void streamDownstreamCall_setsHostHeaderCorrectly(int downstreamPort, boolean isSecure, String downstreamHost, String expectedHostHeader) { // given DefaultHttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, ""); ChannelHandlerContext ctx = mockChannelHandlerContext(); StreamingCallback streamingCallback = mock(StreamingCallback.class); // when new StreamingAsyncHttpClient( 200, 200, true, mock(DistributedTracingConfig.class) ).streamDownstreamCall( downstreamHost, downstreamPort, request, isSecure, false, streamingCallback, 200, true, true, ctx ); // then assertThat(request.headers().get(HOST)).isEqualTo(expectedHostHeader); }
streamingAsyncHttpClient.streamDownstreamCall( downstreamHost, downstreamPort, downstreamRequestFirstChunk, isSecureHttpsCall, relaxedHttpsValidation, callback, callTimeoutValueToUse,
this.debugChannelLifecycleLoggingEnabled = debugChannelLifecycleLoggingEnabled; this.streamingAsyncHttpClientForProxyRouterEndpoints = new StreamingAsyncHttpClient( workerChannelIdleTimeoutMillis, proxyRouterConnectTimeoutMillis,
@Override public Future<Boolean> isHealthy(Channel channel) { // See if we've marked the channel as being non-usable first. if (channelIsMarkedAsBeingBroken(channel)) return channel.eventLoop().newSucceededFuture(Boolean.FALSE); // We haven't marked it broken, so fallback to the default channel health checker. return ChannelHealthChecker.ACTIVE.isHealthy(channel); } }
@Override protected SimpleChannelPool newPool(InetSocketAddress key) { return new SimpleChannelPool( generateClientBootstrap(eventLoopGroup, channelClass).remoteAddress(key), new ChannelPoolHandlerImpl(), CHANNEL_HEALTH_CHECK_INSTANCE
+ "NIO. proxy_router_using_native_epoll_transport=true" ); eventLoopGroup = new EpollEventLoopGroup(0, createProxyRouterThreadFactory()); channelClass = EpollSocketChannel.class; + "proxy_router_using_native_epoll_transport=false" ); eventLoopGroup = new NioEventLoopGroup(0, createProxyRouterThreadFactory()); channelClass = NioSocketChannel.class;
markChannelAsBroken(ch); releaseChannelBackToPoolIfCallIsActive( ch, pool, callActiveHolder, "error received in downstream pipeline: " + cause.toString(), distributedSpanStackToUse, mdcContextToUse addOrReplacePipelineHandler( new DownstreamIdleChannelTimeoutHandler( downstreamCallTimeoutMillis, () -> callActiveHolder.heldObject, true, if (pipelineContainsHttpClientCodec) { HttpClientCodec currentCodec = (HttpClientCodec) p.get(HTTP_CLIENT_CODEC_HANDLER_NAME); int currentHttpClientCodecInboundState = determineHttpClientCodecInboundState(currentCodec); if (currentHttpClientCodecInboundState != 0) { runnableWithTracingAndMdc( int currentHttpClientCodecOutboundState = determineHttpClientCodecOutboundState(currentCodec); if (currentHttpClientCodecOutboundState != 0) { runnableWithTracingAndMdc( addOrReplacePipelineHandler( new HttpClientCodec(4096, 8192, 8192, true), HTTP_CLIENT_CODEC_HANDLER_NAME, p, registeredHandlerNames ); addOrReplacePipelineHandler(chunkSenderHandler, CHUNK_SENDER_HANDLER_NAME, p, registeredHandlerNames); addOrReplacePipelineHandler(errorHandler, ERROR_HANDLER_NAME, p, registeredHandlerNames);
streamingAsyncHttpClient.streamDownstreamCall( downstreamHost, downstreamPort, downstreamRequestFirstChunk, isSecureHttpsCall, relaxedHttpsValidation, callback, callTimeoutValueToUse,
this.debugChannelLifecycleLoggingEnabled = debugChannelLifecycleLoggingEnabled; this.streamingAsyncHttpClientForProxyRouterEndpoints = new StreamingAsyncHttpClient( workerChannelIdleTimeoutMillis, proxyRouterConnectTimeoutMillis,
@Override public Future<Boolean> isHealthy(Channel channel) { // See if we've marked the channel as being non-usable first. if (channelIsMarkedAsBeingBroken(channel)) return channel.eventLoop().newSucceededFuture(Boolean.FALSE); // We haven't marked it broken, so fallback to the default channel health checker. return ChannelHealthChecker.ACTIVE.isHealthy(channel); } }
@Override protected SimpleChannelPool newPool(InetSocketAddress key) { return new SimpleChannelPool( generateClientBootstrap(eventLoopGroup, channelClass).remoteAddress(key), new ChannelPoolHandlerImpl(), CHANNEL_HEALTH_CHECK_INSTANCE
+ "NIO. proxy_router_using_native_epoll_transport=true" ); eventLoopGroup = new EpollEventLoopGroup(0, createProxyRouterThreadFactory()); channelClass = EpollSocketChannel.class; + "proxy_router_using_native_epoll_transport=false" ); eventLoopGroup = new NioEventLoopGroup(0, createProxyRouterThreadFactory()); channelClass = NioSocketChannel.class;
protected static void markChannelBrokenAndLogInfoIfHttpClientCodecStateIsNotZero(Channel ch, String callContextForLogs) { HttpClientCodec currentCodec = (HttpClientCodec) ch.pipeline().get(HTTP_CLIENT_CODEC_HANDLER_NAME); if (currentCodec != null) { int currentHttpClientCodecInboundState = determineHttpClientCodecInboundState(currentCodec); if (currentHttpClientCodecInboundState != 0) { boolean channelAlreadyBroken = channelIsMarkedAsBeingBroken(ch); logger.warn( "HttpClientCodec inbound state was not 0. The channel will be marked as broken so it won't be " + "used. bad_httpclientcodec_inbound_state={}, channel_already_broken={}, channel_id={}, " + "call_context=\"{}\"", currentHttpClientCodecInboundState, channelAlreadyBroken, ch.toString(), callContextForLogs ); markChannelAsBroken(ch); } else { int currentHttpClientCodecOutboundState = determineHttpClientCodecOutboundState(currentCodec); if (currentHttpClientCodecOutboundState != 0) { boolean channelAlreadyBroken = channelIsMarkedAsBeingBroken(ch); logger.warn( "HttpClientCodec outbound state was not 0. The channel will be marked as broken so it won't be " + "used. bad_httpclientcodec_outbound_state={}, channel_already_broken={}, channel_id={}, " + "call_context=\"{}\"", currentHttpClientCodecOutboundState, channelAlreadyBroken, ch.toString(), callContextForLogs ); markChannelAsBroken(ch); } } } }
protected ChannelPool getPooledChannelFuture(String downstreamHost, int downstreamPort) { return getPoolMap().get( resolveHostnameToInetSocketAddressWithMultiIpSupport(downstreamHost, downstreamPort) ); }
/** * Returns the name that should be used for the span surrounding the downstream call. Defaults to whatever {@link * ProxyRouterSpanNamingAndTaggingStrategy#getInitialSpanName(Object)} returns, with a fallback * of {@link HttpRequestTracingUtils#getFallbackSpanNameForHttpRequest(String, String)} if the naming strategy * returned null or blank string. * * @param downstreamRequest The Netty {@link HttpRequest} for the downstream call. * @param namingStrategy The {@link ProxyRouterSpanNamingAndTaggingStrategy} being used. * @return The name that should be used for the span surrounding the downstream call. */ protected @NotNull String getSubspanSpanName( @NotNull HttpRequest downstreamRequest, @NotNull ProxyRouterSpanNamingAndTaggingStrategy<Span> namingStrategy ) { String spanNameFromStrategy = namingStrategy.getInitialSpanName(downstreamRequest); if (StringUtils.isNotBlank(spanNameFromStrategy)) { return spanNameFromStrategy; } // The naming strategy didn't have anything for us. Fall back to something reasonable. return getFallbackSpanName(downstreamRequest); }