use of com.linkedin.r2.message.Response in project rest.li by linkedin.
the class RestLiServer method handleResourceRequest.
private void handleResourceRequest(final RestRequest request, final RequestContext requestContext, final RequestExecutionCallback<RestResponse> callback, final RestLiAttachmentReader attachmentReader, final boolean isDebugMode) {
try {
ensureRequestUsesValidRestliProtocol(request);
} catch (RestLiServiceException e) {
respondWithPreRoutingError(e, request, attachmentReader, callback);
return;
}
final RoutingResult method;
try {
method = _router.process(request, requestContext, attachmentReader);
} catch (Exception e) {
respondWithPreRoutingError(e, request, attachmentReader, callback);
return;
}
final RequestExecutionCallback<RestResponse> wrappedCallback = notifyInvokeAwares(method, callback);
RequestExecutionReportBuilder requestExecutionReportBuilder = null;
if (isDebugMode) {
requestExecutionReportBuilder = new RequestExecutionReportBuilder();
}
final FilterRequestContextInternal filterContext = new FilterRequestContextInternalImpl((ServerResourceContext) method.getContext(), method.getResourceMethod());
RestLiArgumentBuilder adapter;
try {
RestUtils.validateRequestHeadersAndUpdateResourceContext(request.getHeaders(), (ServerResourceContext) method.getContext());
adapter = buildRestLiArgumentBuilder(method, _errorResponseBuilder);
filterContext.setRequestData(adapter.extractRequestData(method, request));
} catch (Exception e) {
// would not trigger response filters because request filters haven't run yet
wrappedCallback.onError(e, requestExecutionReportBuilder == null ? null : requestExecutionReportBuilder.build(), ((ServerResourceContext) method.getContext()).getRequestAttachmentReader(), null);
return;
}
RestLiFilterResponseContextFactory<Object> filterResponseContextFactory = new RestLiFilterResponseContextFactory<Object>(request, method, _responseHandler);
FilterChainCallback filterChainCallback = new FilterChainCallbackImpl(method, _methodInvoker, adapter, requestExecutionReportBuilder, attachmentReader, _responseHandler, wrappedCallback);
RestLiFilterChain filterChain = new RestLiFilterChain(_filters, filterChainCallback);
filterChain.onRequest(filterContext, filterResponseContextFactory);
}
use of com.linkedin.r2.message.Response in project rest.li by linkedin.
the class TestBackupRequestsClient method testStatsConsumerRemoveOne.
@Test(dataProvider = "isD2Async")
public void testStatsConsumerRemoveOne(boolean isD2Async) throws Exception {
AtomicReference<ServiceProperties> serviceProperties = new AtomicReference<>();
TestBackupRequestsStrategyStatsConsumer statsConsumer = new TestBackupRequestsStrategyStatsConsumer();
serviceProperties.set(createServiceProperties(null));
BackupRequestsClient client = createClient(serviceProperties::get, statsConsumer, isD2Async);
URI uri = URI.create("d2://testService");
RestRequest restRequest = new RestRequestBuilder(uri).setEntity(CONTENT).build();
RequestContext requestContext = new RequestContext();
requestContext.putLocalAttr(R2Constants.OPERATION, "get");
Future<RestResponse> response = client.restRequest(restRequest, requestContext);
assertEquals(response.get().getStatus(), 200);
List<StatsConsumerEvent> events = statsConsumer.getEvents();
assertEquals(events.size(), 0);
serviceProperties.set(createServiceProperties(Arrays.asList(createBackupRequestsConfiguration(5, "get"), createBackupRequestsConfiguration(1, "batch_get"))));
requestContext = new RequestContext();
requestContext.putLocalAttr(R2Constants.OPERATION, "get");
response = client.restRequest(restRequest, requestContext);
assertEquals(response.get().getStatus(), 200);
events = statsConsumer.getEvents();
assertEquals(events.size(), 2);
assertEquals(events.get(0).isEventAdd(), true);
assertEquals(events.get(0).getService(), SERVICE_NAME);
assertEquals(events.get(0).getOperation(), "get");
BackupRequestsStrategyStatsProvider statsProvider1 = events.get(0).getStatsProvider();
assertNotNull(statsProvider1);
assertEquals(events.get(1).isEventAdd(), true);
assertEquals(events.get(1).getService(), SERVICE_NAME);
assertEquals(events.get(1).getOperation(), "batch_get");
BackupRequestsStrategyStatsProvider statsProvider2 = events.get(1).getStatsProvider();
assertNotNull(statsProvider2);
serviceProperties.set(createServiceProperties(Arrays.asList(createBackupRequestsConfiguration(5, "get"))));
requestContext = new RequestContext();
requestContext.putLocalAttr(R2Constants.OPERATION, "get");
response = client.restRequest(restRequest, requestContext);
assertEquals(response.get().getStatus(), 200);
events = statsConsumer.getEvents();
assertEquals(events.size(), 3);
assertEquals(events.get(2).isEventAdd(), false);
assertEquals(events.get(2).getService(), SERVICE_NAME);
assertEquals(events.get(2).getOperation(), "batch_get");
BackupRequestsStrategyStatsProvider removedStatsProvider = events.get(2).getStatsProvider();
assertNotNull(removedStatsProvider);
assertSame(statsProvider2, removedStatsProvider);
}
use of com.linkedin.r2.message.Response in project rest.li by linkedin.
the class TestBackupRequestsClient method testRequestWithHint.
/**
* Backup Request should still work when a hint is given together with the flag indicating that the hint is only a preference, not requirement.
*/
// Appears to be flaky in CI
@Test(invocationCount = 3, dataProvider = "isD2Async", retryAnalyzer = SingleRetry.class)
public void testRequestWithHint(boolean isD2Async) throws Exception {
// 1s till response comes back
int responseDelayNano = 100000000;
// make backup request after 0.5 second
int backupDelayNano = 50000000;
Deque<URI> hostsReceivingRequest = new ConcurrentLinkedDeque<>();
BackupRequestsClient client = createAlwaysBackupClientWithHosts(Arrays.asList("http://test1.com:123", "http://test2.com:123"), hostsReceivingRequest, responseDelayNano, backupDelayNano, isD2Async);
URI uri = URI.create("d2://testService");
RestRequest restRequest = new RestRequestBuilder(uri).setEntity(CONTENT).build();
RequestContext context = new RequestContext();
context.putLocalAttr(R2Constants.OPERATION, "get");
// case 1: no hint, backup request should be made normally
RequestContext context1 = context.clone();
Future<RestResponse> response1 = client.restRequest(restRequest, context1);
assertEquals(response1.get().getStatus(), 200);
assertEquals(hostsReceivingRequest.size(), 2);
assertEquals(new HashSet<>(hostsReceivingRequest).size(), 2);
hostsReceivingRequest.clear();
// case 2: hint specified but won't accept other host, backup request will not be made.
RequestContext context2 = context.clone();
URI hint = new URI("http://test1.com:123");
KeyMapper.TargetHostHints.setRequestContextTargetHost(context2, hint);
Future<RestResponse> response2 = client.restRequest(restRequest, context2);
assertEquals(response2.get().getStatus(), 200);
assertEquals(hostsReceivingRequest.size(), 1);
assertEquals(hostsReceivingRequest.poll(), hint);
hostsReceivingRequest.clear();
// case 3: hint specified and set flag to accept other host, backup request will be made to a different host.
RequestContext context3 = context.clone();
KeyMapper.TargetHostHints.setRequestContextTargetHost(context3, hint);
KeyMapper.TargetHostHints.setRequestContextOtherHostAcceptable(context3, true);
Future<RestResponse> response3 = client.restRequest(restRequest, context3);
assertEquals(response3.get().getStatus(), 200);
assertEquals(hostsReceivingRequest.size(), 2);
// The first request should be made to the hinted host while the second should go to the other.
assertEquals(hostsReceivingRequest.toArray(), new URI[] { new URI("http://test1.com:123"), new URI("http://test2.com:123") });
assertEquals(new HashSet<>(hostsReceivingRequest).size(), 2);
}
use of com.linkedin.r2.message.Response in project rest.li by linkedin.
the class TestBackupRequestsClient method testStreamRequestWithNoIsFullRequest.
@Test(invocationCount = 3, dataProvider = "isD2Async")
public void testStreamRequestWithNoIsFullRequest(boolean isD2Async) throws Exception {
// 1s till response comes back
int responseDelayNano = 100000000;
// make backup request after 0.5 second
int backupDelayNano = 50000000;
Deque<URI> hostsReceivingRequest = new ConcurrentLinkedDeque<>();
BackupRequestsClient client = createAlwaysBackupClientWithHosts(Arrays.asList("http://test1.com:123", "http://test2.com:123"), hostsReceivingRequest, responseDelayNano, backupDelayNano, isD2Async);
URI uri = URI.create("d2://testService");
// if there is no IS_FULL_REQUEST set, backup requests will not happen
StreamRequest streamRequest = new StreamRequestBuilder(uri).build(EntityStreams.newEntityStream(new ByteStringWriter(CONTENT)));
RequestContext context = new RequestContext();
context.putLocalAttr(R2Constants.OPERATION, "get");
RequestContext context1 = context.clone();
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<AssertionError> failure = new AtomicReference<>();
client.streamRequest(streamRequest, context1, new Callback<StreamResponse>() {
@Override
public void onError(Throwable e) {
failure.set(new AssertionError("Callback onError"));
latch.countDown();
}
@Override
public void onSuccess(StreamResponse result) {
try {
assertEquals(result.getStatus(), 200);
assertEquals(result.getHeader("buffered"), "false");
assertEquals(hostsReceivingRequest.size(), 1);
assertEquals(new HashSet<>(hostsReceivingRequest).size(), 1);
hostsReceivingRequest.clear();
} catch (AssertionError e) {
failure.set(e);
}
latch.countDown();
}
});
latch.await(2, TimeUnit.SECONDS);
if (failure.get() != null) {
throw failure.get();
}
}
use of com.linkedin.r2.message.Response in project rest.li by linkedin.
the class DegraderTrackerClientTest method testCallTrackingStreamRequest.
@Test
public void testCallTrackingStreamRequest() throws Exception {
URI uri = URI.create("http://test.qa.com:1234/foo");
SettableClock clock = new SettableClock();
AtomicInteger action = new AtomicInteger(0);
TransportClient tc = new TransportClient() {
@Override
public void restRequest(RestRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<RestResponse> callback) {
}
@Override
public void streamRequest(StreamRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<StreamResponse> callback) {
clock.addDuration(5);
switch(action.get()) {
// success
case 0:
callback.onResponse(TransportResponseImpl.success(new StreamResponseBuilder().build(EntityStreams.emptyStream())));
break;
// fail with stream exception
case 1:
callback.onResponse(TransportResponseImpl.error(new StreamException(new StreamResponseBuilder().setStatus(500).build(EntityStreams.emptyStream()))));
break;
// fail with timeout exception
case 2:
callback.onResponse(TransportResponseImpl.error(new RemoteInvocationException(new TimeoutException())));
break;
// fail with other exception
default:
callback.onResponse(TransportResponseImpl.error(new RuntimeException()));
break;
}
}
@Override
public void shutdown(Callback<None> callback) {
}
};
DegraderTrackerClientImpl client = (DegraderTrackerClientImpl) createTrackerClient(tc, clock, uri);
CallTracker callTracker = client.getCallTracker();
CallTracker.CallStats stats;
DegraderControl degraderControl = client.getDegraderControl(DefaultPartitionAccessor.DEFAULT_PARTITION_ID);
DelayConsumeCallback delayConsumeCallback = new DelayConsumeCallback();
client.streamRequest(new StreamRequestBuilder(uri).build(EntityStreams.emptyStream()), new RequestContext(), new HashMap<>(), delayConsumeCallback);
clock.addDuration(5);
// we only recorded the time when stream response arrives, but callcompletion.endcall hasn't been called yet.
Assert.assertEquals(callTracker.getCurrentCallCountTotal(), 0);
Assert.assertEquals(callTracker.getCurrentErrorCountTotal(), 0);
// delay
clock.addDuration(100);
delayConsumeCallback.consume();
clock.addDuration(5000);
// now that we consumed the entity stream, callcompletion.endcall has been called.
stats = callTracker.getCallStats();
Assert.assertEquals(stats.getCallCount(), 1);
Assert.assertEquals(stats.getErrorCount(), 0);
Assert.assertEquals(stats.getCallCountTotal(), 1);
Assert.assertEquals(stats.getErrorCountTotal(), 0);
Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.0, 0.001);
action.set(1);
client.streamRequest(new StreamRequestBuilder(uri).build(EntityStreams.emptyStream()), new RequestContext(), new HashMap<>(), delayConsumeCallback);
clock.addDuration(5);
// we endcall with error immediately for stream exception, even before the entity is consumed
Assert.assertEquals(callTracker.getCurrentCallCountTotal(), 2);
Assert.assertEquals(callTracker.getCurrentErrorCountTotal(), 1);
delayConsumeCallback.consume();
clock.addDuration(5000);
// no change in tracking after entity is consumed
stats = callTracker.getCallStats();
Assert.assertEquals(stats.getCallCount(), 1);
Assert.assertEquals(stats.getErrorCount(), 1);
Assert.assertEquals(stats.getCallCountTotal(), 2);
Assert.assertEquals(stats.getErrorCountTotal(), 1);
Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.2, 0.001);
action.set(2);
client.streamRequest(new StreamRequestBuilder(uri).build(EntityStreams.emptyStream()), new RequestContext(), new HashMap<>(), new TestTransportCallback<>());
clock.addDuration(5);
Assert.assertEquals(callTracker.getCurrentCallCountTotal(), 3);
Assert.assertEquals(callTracker.getCurrentErrorCountTotal(), 2);
clock.addDuration(5000);
stats = callTracker.getCallStats();
Assert.assertEquals(stats.getCallCount(), 1);
Assert.assertEquals(stats.getErrorCount(), 1);
Assert.assertEquals(stats.getCallCountTotal(), 3);
Assert.assertEquals(stats.getErrorCountTotal(), 2);
Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.4, 0.001);
action.set(3);
client.streamRequest(new StreamRequestBuilder(uri).build(EntityStreams.emptyStream()), new RequestContext(), new HashMap<>(), new TestTransportCallback<>());
clock.addDuration(5);
Assert.assertEquals(callTracker.getCurrentCallCountTotal(), 4);
Assert.assertEquals(callTracker.getCurrentErrorCountTotal(), 3);
clock.addDuration(5000);
stats = callTracker.getCallStats();
Assert.assertEquals(stats.getCallCount(), 1);
Assert.assertEquals(stats.getErrorCount(), 1);
Assert.assertEquals(stats.getCallCountTotal(), 4);
Assert.assertEquals(stats.getErrorCountTotal(), 3);
Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.2, 0.001);
}
Aggregations