use of com.nike.riposte.metrics.MetricsListener in project riposte by Nike-Inc.
the class HttpChannelInitializerTest method constructor_works_with_valid_args.
@Test
public void constructor_works_with_valid_args() {
// given
SslContext sslCtx = mock(SslContext.class);
int maxRequestSizeInBytes = 42;
Collection<Endpoint<?>> endpoints = Arrays.asList(getMockEndpoint("/some/path", HttpMethod.GET));
RequestAndResponseFilter beforeSecurityRequestFilter = mock(RequestAndResponseFilter.class);
doReturn(true).when(beforeSecurityRequestFilter).shouldExecuteBeforeSecurityValidation();
RequestAndResponseFilter afterSecurityRequestFilter = mock(RequestAndResponseFilter.class);
doReturn(false).when(afterSecurityRequestFilter).shouldExecuteBeforeSecurityValidation();
List<RequestAndResponseFilter> reqResFilters = Arrays.asList(beforeSecurityRequestFilter, afterSecurityRequestFilter);
Executor longRunningTaskExecutor = mock(Executor.class);
RiposteErrorHandler riposteErrorHandler = mock(RiposteErrorHandler.class);
RiposteUnhandledErrorHandler riposteUnhandledErrorHandler = mock(RiposteUnhandledErrorHandler.class);
RequestValidator validationService = mock(RequestValidator.class);
ObjectMapper requestContentDeserializer = mock(ObjectMapper.class);
ResponseSender responseSender = mock(ResponseSender.class);
@SuppressWarnings("unchecked") MetricsListener metricsListener = mock(MetricsListener.class);
long defaultCompletableFutureTimeoutMillis = 4242L;
AccessLogger accessLogger = mock(AccessLogger.class);
List<PipelineCreateHook> pipelineCreateHooks = mock(List.class);
RequestSecurityValidator requestSecurityValidator = mock(RequestSecurityValidator.class);
long workerChannelIdleTimeoutMillis = 121000;
long proxyRouterConnectTimeoutMillis = 4200;
long incompleteHttpCallTimeoutMillis = 1234;
int maxOpenChannelsThreshold = 1000;
boolean debugChannelLifecycleLoggingEnabled = true;
List<String> userIdHeaderKeys = mock(List.class);
// when
HttpChannelInitializer hci = new HttpChannelInitializer(sslCtx, maxRequestSizeInBytes, endpoints, reqResFilters, longRunningTaskExecutor, riposteErrorHandler, riposteUnhandledErrorHandler, validationService, requestContentDeserializer, responseSender, metricsListener, defaultCompletableFutureTimeoutMillis, accessLogger, pipelineCreateHooks, requestSecurityValidator, workerChannelIdleTimeoutMillis, proxyRouterConnectTimeoutMillis, incompleteHttpCallTimeoutMillis, maxOpenChannelsThreshold, debugChannelLifecycleLoggingEnabled, userIdHeaderKeys);
// then
assertThat(extractField(hci, "sslCtx"), is(sslCtx));
assertThat(extractField(hci, "maxRequestSizeInBytes"), is(maxRequestSizeInBytes));
assertThat(extractField(hci, "endpoints"), is(endpoints));
assertThat(extractField(hci, "longRunningTaskExecutor"), is(longRunningTaskExecutor));
assertThat(extractField(hci, "riposteErrorHandler"), is(riposteErrorHandler));
assertThat(extractField(hci, "riposteUnhandledErrorHandler"), is(riposteUnhandledErrorHandler));
assertThat(extractField(hci, "validationService"), is(validationService));
assertThat(extractField(hci, "requestContentDeserializer"), is(requestContentDeserializer));
assertThat(extractField(hci, "responseSender"), is(responseSender));
assertThat(extractField(hci, "metricsListener"), is(metricsListener));
assertThat(extractField(hci, "defaultCompletableFutureTimeoutMillis"), is(defaultCompletableFutureTimeoutMillis));
assertThat(extractField(hci, "accessLogger"), is(accessLogger));
assertThat(extractField(hci, "pipelineCreateHooks"), is(pipelineCreateHooks));
assertThat(extractField(hci, "requestSecurityValidator"), is(requestSecurityValidator));
assertThat(extractField(hci, "workerChannelIdleTimeoutMillis"), is(workerChannelIdleTimeoutMillis));
assertThat(extractField(hci, "incompleteHttpCallTimeoutMillis"), is(incompleteHttpCallTimeoutMillis));
assertThat(extractField(hci, "maxOpenChannelsThreshold"), is(maxOpenChannelsThreshold));
assertThat(extractField(hci, "debugChannelLifecycleLoggingEnabled"), is(debugChannelLifecycleLoggingEnabled));
assertThat(extractField(hci, "userIdHeaderKeys"), is(userIdHeaderKeys));
StreamingAsyncHttpClient sahc = extractField(hci, "streamingAsyncHttpClientForProxyRouterEndpoints");
assertThat(extractField(sahc, "idleChannelTimeoutMillis"), is(workerChannelIdleTimeoutMillis));
assertThat(extractField(sahc, "downstreamConnectionTimeoutMillis"), is((int) proxyRouterConnectTimeoutMillis));
assertThat(extractField(sahc, "debugChannelLifecycleLoggingEnabled"), is(debugChannelLifecycleLoggingEnabled));
RequestFilterHandler beforeSecReqFH = extractField(hci, "beforeSecurityRequestFilterHandler");
assertThat(extractField(beforeSecReqFH, "filters"), is(Collections.singletonList(beforeSecurityRequestFilter)));
RequestFilterHandler afterSecReqFH = extractField(hci, "afterSecurityRequestFilterHandler");
assertThat(extractField(afterSecReqFH, "filters"), is(Collections.singletonList(afterSecurityRequestFilter)));
ResponseFilterHandler resFH = extractField(hci, "cachedResponseFilterHandler");
List<RequestAndResponseFilter> reversedFilters = new ArrayList<>(reqResFilters);
Collections.reverse(reversedFilters);
assertThat(extractField(resFH, "filtersInResponseProcessingOrder"), is(reversedFilters));
}
use of com.nike.riposte.metrics.MetricsListener in project riposte by Nike-Inc.
the class HttpChannelInitializerTest method initChannel_adds_ChannelPipelineFinalizerHandler_as_the_last_handler_and_uses_the_ExceptionHandlingHandler_handler_and_responseSender_and_metricsListener.
@Test
public void initChannel_adds_ChannelPipelineFinalizerHandler_as_the_last_handler_and_uses_the_ExceptionHandlingHandler_handler_and_responseSender_and_metricsListener() {
// given
HttpChannelInitializer hci = basicHttpChannelInitializerNoUtilityHandlers();
MetricsListener expectedMetricsListener = mock(MetricsListener.class);
Whitebox.setInternalState(hci, "metricsListener", expectedMetricsListener);
ResponseSender expectedResponseSender = extractField(hci, "responseSender");
// when
hci.initChannel(socketChannelMock);
// then
ArgumentCaptor<ChannelHandler> channelHandlerArgumentCaptor = ArgumentCaptor.forClass(ChannelHandler.class);
verify(channelPipelineMock, atLeastOnce()).addLast(anyString(), channelHandlerArgumentCaptor.capture());
List<ChannelHandler> handlers = channelHandlerArgumentCaptor.getAllValues();
Pair<Integer, ChannelPipelineFinalizerHandler> channelPipelineFinalizerHandler = findChannelHandler(handlers, ChannelPipelineFinalizerHandler.class);
assertThat(channelPipelineFinalizerHandler, notNullValue());
assertThat(channelPipelineFinalizerHandler.getLeft(), is(handlers.size() - 1));
// and then
Pair<Integer, ExceptionHandlingHandler> expectedExceptionHandlingHandlerPair = findChannelHandler(handlers, ExceptionHandlingHandler.class);
assertThat(expectedExceptionHandlingHandlerPair, notNullValue());
ExceptionHandlingHandler actualExceptionHandlingHandler = (ExceptionHandlingHandler) Whitebox.getInternalState(channelPipelineFinalizerHandler.getRight(), "exceptionHandlingHandler");
ResponseSender actualResponseSender = (ResponseSender) Whitebox.getInternalState(channelPipelineFinalizerHandler.getRight(), "responseSender");
MetricsListener actualMetricsListener = (MetricsListener) Whitebox.getInternalState(channelPipelineFinalizerHandler.getRight(), "metricsListener");
assertThat(actualExceptionHandlingHandler, is(expectedExceptionHandlingHandlerPair.getRight()));
assertThat(actualResponseSender, is(expectedResponseSender));
assertThat(actualMetricsListener, is(expectedMetricsListener));
}
use of com.nike.riposte.metrics.MetricsListener in project riposte by Nike-Inc.
the class ChannelPipelineFinalizerHandler method finalizeChannelPipeline.
/**
* This will first check the given state to see if a response was sent to the user. If not then this method will
* send a generic error to the user so they get some response (so this method is kind of a backstop in case requests
* somehow slip through our pipeline without being handled, which should never happen, but we have to have this just
* in case). Then it will clean out the state so that it is ready for the next request.
* <p/>
* If the state indicates that a response was already sent then this method will only clean out the state for the
* next request and will not send an error.
*/
protected void finalizeChannelPipeline(ChannelHandlerContext ctx, Object msg, HttpProcessingState state, Throwable cause) throws JsonProcessingException {
RequestInfo<?> requestInfo = exceptionHandlingHandler.getRequestInfo(state, msg);
// is sent it will update the state.isResponseSent() so that further calls will return true.
if (!state.isResponseSendingStarted()) {
String errorMsg = "Discovered a request that snuck through without a response being sent. This should not " + "be possible and indicates a major problem in the channel pipeline.";
logger.error(errorMsg, new Exception("Wrapper exception", cause));
// Send a generic unhandled error response with a wrapper exception so that the logging info output by the
// exceptionHandlingHandler will have the overview of what went wrong.
Exception exceptionToUse = new Exception(errorMsg, cause);
ResponseInfo<ErrorResponseBody> responseInfo = exceptionHandlingHandler.processUnhandledError(state, msg, exceptionToUse);
responseSender.sendErrorResponse(ctx, requestInfo, responseInfo);
}
ctx.flush();
// the metrics for this request, so make sure we only do it if appropriate.
if (metricsListener != null && !state.isRequestMetricsRecordedOrScheduled()) {
// conditions), otherwise do it when the response finishes.
if (!state.isResponseSendingLastChunkSent()) {
// TODO: Somehow mark the state as a failed request and update the metrics listener to handle it
metricsListener.onEvent(ServerMetricsEvent.RESPONSE_SENT, state);
} else {
// We need to use a copy of the state in case the original state gets cleaned.
HttpProcessingState stateCopy = new HttpProcessingState(state);
stateCopy.getResponseWriterFinalChunkChannelFuture().addListener((ChannelFutureListener) channelFuture -> {
if (channelFuture.isSuccess())
metricsListener.onEvent(ServerMetricsEvent.RESPONSE_SENT, stateCopy);
else {
metricsListener.onEvent(ServerMetricsEvent.RESPONSE_WRITE_FAILED, null);
}
});
}
state.setRequestMetricsRecordedOrScheduled(true);
}
// Make sure to clear out request info chunks, multipart data, and any other resources to prevent reference
// counting memory leaks (or any other kind of memory leaks).
requestInfo.releaseAllResources();
// channel if it sits unused longer than the timeout value before the next request arrives.
if (workerChannelIdleTimeoutMillis > 0 && ctx.pipeline().get(IDLE_CHANNEL_TIMEOUT_HANDLER_NAME) == null) {
ctx.pipeline().addFirst(IDLE_CHANNEL_TIMEOUT_HANDLER_NAME, new IdleChannelTimeoutHandler(workerChannelIdleTimeoutMillis, "ServerWorkerChannel"));
}
// request is broken. We can't do anything except kill the channel.
if ((cause != null) && state.isResponseSendingStarted() && !state.isResponseSendingLastChunkSent()) {
runnableWithTracingAndMdc(() -> logger.error("Received an error in ChannelPipelineFinalizerHandler after response sending was started, but " + "before it finished. Closing the channel. unexpected_error={}", cause.toString()), ctx).run();
ctx.channel().close();
}
}
use of com.nike.riposte.metrics.MetricsListener in project riposte by Nike-Inc.
the class HttpChannelInitializerTest method initChannel_adds_RequestStateCleanerHandler_immediately_after_HttpRequestDecoder.
@Test
public void initChannel_adds_RequestStateCleanerHandler_immediately_after_HttpRequestDecoder() {
// given
HttpChannelInitializer hci = basicHttpChannelInitializerNoUtilityHandlers();
MetricsListener expectedMetricsListener = mock(MetricsListener.class);
long expectedIncompleteCallTimeoutMillis = 424242;
Whitebox.setInternalState(hci, "metricsListener", expectedMetricsListener);
Whitebox.setInternalState(hci, "incompleteHttpCallTimeoutMillis", expectedIncompleteCallTimeoutMillis);
// when
hci.initChannel(socketChannelMock);
// then
ArgumentCaptor<ChannelHandler> channelHandlerArgumentCaptor = ArgumentCaptor.forClass(ChannelHandler.class);
verify(channelPipelineMock, atLeastOnce()).addLast(anyString(), channelHandlerArgumentCaptor.capture());
List<ChannelHandler> handlers = channelHandlerArgumentCaptor.getAllValues();
Pair<Integer, HttpRequestDecoder> httpRequestDecoderHandler = findChannelHandler(handlers, HttpRequestDecoder.class);
Pair<Integer, RequestStateCleanerHandler> requestStateCleanerHandler = findChannelHandler(handlers, RequestStateCleanerHandler.class);
assertThat(httpRequestDecoderHandler, notNullValue());
assertThat(requestStateCleanerHandler, notNullValue());
assertThat(requestStateCleanerHandler.getLeft(), is(httpRequestDecoderHandler.getLeft() + 1));
RequestStateCleanerHandler handler = requestStateCleanerHandler.getRight();
assertThat(Whitebox.getInternalState(hci, "metricsListener"), is(expectedMetricsListener));
assertThat(Whitebox.getInternalState(hci, "incompleteHttpCallTimeoutMillis"), is(expectedIncompleteCallTimeoutMillis));
}
Aggregations