use of com.linkedin.common.callback.Callback in project rest.li by linkedin.
the class TestHttpNettyStreamClient method testStreamRequests.
/**
* Tests implementations of {@link AbstractNettyStreamClient} with different request dimensions.
*
* @param client Client implementation of {@link AbstractNettyStreamClient}
* @param method HTTP request method
* @param requestSize Request content size
* @param responseSize Response content size
* @param isFullRequest Whether to buffer a full request before stream
* @throws Exception
*/
@Test(dataProvider = "requestResponseParameters")
public void testStreamRequests(AbstractNettyStreamClient client, String method, int requestSize, int responseSize, boolean isFullRequest) throws Exception {
AtomicInteger succeeded = new AtomicInteger(0);
AtomicInteger failed = new AtomicInteger(0);
Server server = new HttpServerBuilder().responseSize(responseSize).build();
try {
server.start();
CountDownLatch latch = new CountDownLatch(REQUEST_COUNT);
for (int i = 0; i < REQUEST_COUNT; i++) {
StreamRequest request = new StreamRequestBuilder(new URI(URL)).setMethod(method).setHeader(HttpHeaderNames.HOST.toString(), HOST_NAME.toString()).build(EntityStreams.newEntityStream(new ByteStringWriter(ByteString.copy(new byte[requestSize]))));
RequestContext context = new RequestContext();
context.putLocalAttr(R2Constants.IS_FULL_REQUEST, isFullRequest);
client.streamRequest(request, context, new HashMap<>(), new TransportCallbackAdapter<>(new Callback<StreamResponse>() {
@Override
public void onSuccess(StreamResponse response) {
response.getEntityStream().setReader(new Reader() {
ReadHandle _rh;
int _consumed = 0;
@Override
public void onDataAvailable(ByteString data) {
_consumed += data.length();
_rh.request(1);
}
@Override
public void onDone() {
succeeded.incrementAndGet();
latch.countDown();
}
@Override
public void onError(Throwable e) {
failed.incrementAndGet();
latch.countDown();
}
@Override
public void onInit(ReadHandle rh) {
_rh = rh;
_rh.request(1);
}
});
}
@Override
public void onError(Throwable e) {
failed.incrementAndGet();
latch.countDown();
}
}));
}
if (!latch.await(30, TimeUnit.SECONDS)) {
Assert.fail("Timeout waiting for responses. " + succeeded + " requests succeeded and " + failed + " requests failed out of total " + REQUEST_COUNT + " requests");
}
Assert.assertEquals(latch.getCount(), 0);
Assert.assertEquals(failed.get(), 0);
Assert.assertEquals(succeeded.get(), REQUEST_COUNT);
FutureCallback<None> shutdownCallback = new FutureCallback<>();
client.shutdown(shutdownCallback);
shutdownCallback.get(30, TimeUnit.SECONDS);
} finally {
server.stop();
}
}
use of com.linkedin.common.callback.Callback in project rest.li by linkedin.
the class RetryClient method decorateCallback.
private <R, T> Callback<T> decorateCallback(R request, RequestContext requestContext, DecoratorClient<R, T> client, Callback<T> callback) {
return new Callback<T>() {
@Override
public void onError(Throwable e) {
// Retry will be triggered if and only if:
// 1. A RetriableRequestException is thrown
// 2. There is no target host hint
boolean retry = false;
if (e instanceof RetriableRequestException) {
URI targetHostUri = KeyMapper.TargetHostHints.getRequestContextTargetHost(requestContext);
if (targetHostUri == null) {
Set<URI> exclusionSet = ExcludedHostHints.getRequestContextExcludedHosts(requestContext);
int attempts = exclusionSet.size();
if (attempts <= _limit) {
LOG.warn("A retriable exception happens. Going to retry. This is attempt {}. Current exclusion set: ", attempts, ". Current exclusion set: " + exclusionSet);
retry = true;
client.doRequest(request, requestContext, this);
} else {
LOG.warn("Retry limit exceeded. This request will fail.");
}
}
}
if (!retry) {
ExcludedHostHints.clearRequestContextExcludedHosts(requestContext);
callback.onError(e);
}
}
@Override
public void onSuccess(T result) {
ExcludedHostHints.clearRequestContextExcludedHosts(requestContext);
callback.onSuccess(result);
}
};
}
use of com.linkedin.common.callback.Callback in project rest.li by linkedin.
the class Messages method toRestRequest.
/**
* Converts a StreamRequest to RestRequest
* @param streamRequest the stream request to be converted
* @param callback the callback to be invoked when the rest request is constructed
*/
public static void toRestRequest(StreamRequest streamRequest, final Callback<RestRequest> callback) {
final RestRequestBuilder builder = new RestRequestBuilder(streamRequest);
Callback<ByteString> assemblyCallback = new Callback<ByteString>() {
@Override
public void onError(Throwable e) {
callback.onError(e);
}
@Override
public void onSuccess(ByteString result) {
RestRequest restRequest = builder.setEntity(result).build();
callback.onSuccess(restRequest);
}
};
streamRequest.getEntityStream().setReader(new FullEntityReader(assemblyCallback));
}
use of com.linkedin.common.callback.Callback in project rest.li by linkedin.
the class Messages method toRestResponse.
/**
* Converts a StreamResponse to RestResponse
* @param streamResponse the stream request to be converted
* @param callback the callback to be invoked when the rest response is constructed
* @param addContentLengthHeader whether the rest response should have content-length header
*/
public static void toRestResponse(StreamResponse streamResponse, final Callback<RestResponse> callback, final boolean addContentLengthHeader) {
final RestResponseBuilder builder = new RestResponseBuilder(streamResponse);
Callback<ByteString> assemblyCallback = new Callback<ByteString>() {
@Override
public void onError(Throwable e) {
callback.onError(e);
}
@Override
public void onSuccess(ByteString result) {
if (addContentLengthHeader) {
builder.setHeader(HttpConstants.CONTENT_LENGTH, String.valueOf(result.length()));
}
RestResponse restResponse = builder.setEntity(result).build();
callback.onSuccess(restResponse);
}
};
streamResponse.getEntityStream().setReader(new FullEntityReader(assemblyCallback));
}
use of com.linkedin.common.callback.Callback in project rest.li by linkedin.
the class AsyncPoolImpl method get.
@Override
public Cancellable get(final Callback<T> callback) {
// getter needs to add to wait queue atomically with check for empty pool
// putter needs to add to pool atomically with check for empty wait queue
boolean create = false;
boolean reject = false;
final LinkedDeque.Node<Callback<T>> node;
final Callback<T> callbackWithTracking = new TimeTrackingCallback<T>(callback);
for (; ; ) {
TimedObject<T> obj = null;
final State state;
synchronized (_lock) {
state = _state;
if (state == State.RUNNING) {
if (_strategy == Strategy.LRU) {
obj = _idle.pollFirst();
} else {
obj = _idle.pollLast();
}
if (obj == null) {
if (_waiters.size() < _maxWaiters) {
// No objects available and the waiter list is not full; add to waiter list and break out of loop
node = _waiters.addLastNode(callbackWithTracking);
create = shouldCreate();
} else {
reject = true;
node = null;
}
break;
}
}
}
if (state != State.RUNNING) {
// Defer execution of the callback until we are out of the synchronized block
callbackWithTracking.onError(new IllegalStateException(_poolName + " is " + _state));
return () -> false;
}
T rawObj = obj.get();
if (_lifecycle.validateGet(rawObj)) {
trc("dequeued an idle object");
// Valid object; done
synchronized (_lock) {
_checkedOut++;
_statsTracker.sampleMaxCheckedOut();
}
callbackWithTracking.onSuccess(rawObj);
return () -> false;
}
// Invalid object, discard it and keep trying
destroy(rawObj, true);
trc("dequeued and disposed an invalid idle object");
}
if (reject) {
// This is a recoverable exception. User can simply retry the failed get() operation.
callbackWithTracking.onError(new SizeLimitExceededException("AsyncPool " + _poolName + " reached maximum waiter size: " + _maxWaiters));
return null;
}
trc("enqueued a waiter");
if (create) {
create();
}
return new Cancellable() {
@Override
public boolean cancel() {
synchronized (_lock) {
return _waiters.removeNode(node) != null;
}
}
};
}
Aggregations