use of io.netty.util.concurrent.Future in project redisson by redisson.
the class RedissonBlockingFairQueue method tryPollLastAndOfferFirstToAsync.
private void tryPollLastAndOfferFirstToAsync(final long startTime, final long timeout, final TimeUnit unit, final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<V> promise, final String queueName) {
if (promise.isDone()) {
unsubscribe(subscribeFuture);
return;
}
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime <= 0) {
unsubscribe(subscribeFuture);
promise.trySuccess(null);
return;
}
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
unsubscribe(subscribeFuture);
promise.tryFailure(future.cause());
return;
}
Long currentTimeout = future.getNow();
if (currentTimeout == null) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.pollLastAndOfferFirstToAsync(queueName, remainTime, TimeUnit.MILLISECONDS);
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
unsubscribe(subscribeFuture);
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
unsubscribe(subscribeFuture);
promise.trySuccess(null);
}
} else {
final RedissonLockEntry entry = getEntry();
synchronized (entry) {
if (entry.getLatch().tryAcquire()) {
tryPollAsync(startTime, timeout, unit, subscribeFuture, promise);
} else {
final AtomicBoolean executed = new AtomicBoolean();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Runnable listener = new Runnable() {
@Override
public void run() {
executed.set(true);
if (futureRef.get() != null) {
futureRef.get().cancel();
}
tryPollLastAndOfferFirstToAsync(startTime, timeout, unit, subscribeFuture, promise, queueName);
}
};
entry.addListener(listener);
if (!executed.get()) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout t) throws Exception {
synchronized (entry) {
if (entry.removeListener(listener)) {
tryPollLastAndOfferFirstToAsync(startTime, timeout, unit, subscribeFuture, promise, queueName);
}
}
}
}, remainTime, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
}
}
;
});
}
use of io.netty.util.concurrent.Future in project redisson by redisson.
the class RedissonBlockingFairQueue method tryTakeAsync.
private void tryTakeAsync(final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<V> promise) {
if (promise.isDone()) {
unsubscribe(subscribeFuture);
return;
}
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
unsubscribe(subscribeFuture);
promise.tryFailure(future.cause());
return;
}
Long currentTimeout = future.getNow();
if (currentTimeout == null) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.takeAsync();
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
unsubscribe(subscribeFuture);
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
final RedissonLockEntry entry = getEntry();
synchronized (entry) {
if (entry.getLatch().tryAcquire()) {
tryTakeAsync(subscribeFuture, promise);
} else {
final AtomicBoolean executed = new AtomicBoolean();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Runnable listener = new Runnable() {
@Override
public void run() {
executed.set(true);
if (futureRef.get() != null) {
futureRef.get().cancel();
}
tryTakeAsync(subscribeFuture, promise);
}
};
entry.addListener(listener);
if (!executed.get()) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout t) throws Exception {
synchronized (entry) {
if (entry.removeListener(listener)) {
tryTakeAsync(subscribeFuture, promise);
}
}
}
}, currentTimeout, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
}
}
;
});
}
use of io.netty.util.concurrent.Future in project redisson by redisson.
the class RedissonRemoteService method subscribe.
private <T> void subscribe(final Class<T> remoteInterface, final RBlockingQueue<RemoteServiceRequest> requestQueue, final ExecutorService executor) {
RFuture<RemoteServiceRequest> take = requestQueue.takeAsync();
take.addListener(new FutureListener<RemoteServiceRequest>() {
@Override
public void operationComplete(Future<RemoteServiceRequest> future) throws Exception {
if (!future.isSuccess()) {
if (future.cause() instanceof RedissonShutdownException) {
return;
}
log.error("Can't process the remote service request.", future.cause());
// re-subscribe after a failed takeAsync
subscribe(remoteInterface, requestQueue, executor);
return;
}
// do not subscribe now, see
// https://github.com/mrniko/redisson/issues/493
// subscribe(remoteInterface, requestQueue);
final RemoteServiceRequest request = future.getNow();
// check the ack only if expected
if (request.getOptions().isAckExpected() && System.currentTimeMillis() - request.getDate() > request.getOptions().getAckTimeoutInMillis()) {
log.debug("request: {} has been skipped due to ackTimeout");
// re-subscribe after a skipped ackTimeout
subscribe(remoteInterface, requestQueue, executor);
return;
}
final String responseName = getResponseQueueName(remoteInterface, request.getRequestId());
// send the ack only if expected
if (request.getOptions().isAckExpected()) {
String ackName = getAckName(remoteInterface, request.getRequestId());
RFuture<Boolean> ackClientsFuture = commandExecutor.evalWriteAsync(responseName, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "if redis.call('setnx', KEYS[1], 1) == 1 then " + "redis.call('pexpire', KEYS[1], ARGV[2]);" + "redis.call('rpush', KEYS[2], ARGV[1]);" + "redis.call('pexpire', KEYS[2], ARGV[2]);" + "return 1;" + "end;" + "return 0;", Arrays.<Object>asList(ackName, responseName), encode(new RemoteServiceAck()), request.getOptions().getAckTimeoutInMillis());
ackClientsFuture.addListener(new FutureListener<Boolean>() {
@Override
public void operationComplete(Future<Boolean> future) throws Exception {
if (!future.isSuccess()) {
log.error("Can't send ack for request: " + request, future.cause());
if (future.cause() instanceof RedissonShutdownException) {
return;
}
// re-subscribe after a failed send (ack)
subscribe(remoteInterface, requestQueue, executor);
return;
}
if (!future.getNow()) {
subscribe(remoteInterface, requestQueue, executor);
return;
}
executeMethod(remoteInterface, requestQueue, executor, request);
}
});
} else {
executeMethod(remoteInterface, requestQueue, executor, request);
}
}
});
}
use of io.netty.util.concurrent.Future in project redisson by redisson.
the class RedissonKeys method deleteByPatternAsync.
@Override
public RFuture<Long> deleteByPatternAsync(String pattern) {
if (!commandExecutor.getConnectionManager().isClusterMode()) {
return commandExecutor.evalWriteAsync((String) null, null, RedisCommands.EVAL_LONG, "local keys = redis.call('keys', ARGV[1]) " + "local n = 0 " + "for i=1, #keys,5000 do " + "n = n + redis.call('del', unpack(keys, i, math.min(i+4999, table.getn(keys)))) " + "end " + "return n;", Collections.emptyList(), pattern);
}
final RPromise<Long> result = commandExecutor.getConnectionManager().newPromise();
final AtomicReference<Throwable> failed = new AtomicReference<Throwable>();
final AtomicLong count = new AtomicLong();
Set<MasterSlaveEntry> entries = commandExecutor.getConnectionManager().getEntrySet();
final AtomicLong executed = new AtomicLong(entries.size());
final FutureListener<Long> listener = new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (future.isSuccess()) {
count.addAndGet(future.getNow());
} else {
failed.set(future.cause());
}
checkExecution(result, failed, count, executed);
}
};
for (MasterSlaveEntry entry : entries) {
RFuture<Collection<String>> findFuture = commandExecutor.readAsync(entry, null, RedisCommands.KEYS, pattern);
findFuture.addListener(new FutureListener<Collection<String>>() {
@Override
public void operationComplete(Future<Collection<String>> future) throws Exception {
if (!future.isSuccess()) {
failed.set(future.cause());
checkExecution(result, failed, count, executed);
return;
}
Collection<String> keys = future.getNow();
if (keys.isEmpty()) {
checkExecution(result, failed, count, executed);
return;
}
RFuture<Long> deleteFuture = deleteAsync(keys.toArray(new String[keys.size()]));
deleteFuture.addListener(listener);
}
});
}
return result;
}
use of io.netty.util.concurrent.Future in project riposte by Nike-Inc.
the class StreamingAsyncHttpClient method streamDownstreamCall.
/**
* TODO: Fully document me.
* <br/>
* NOTE: The returned CompletableFuture will only be completed successfully if the connection to the downstream
* server was successful and the initialRequestChunk was successfully written out. This has implications for
* initialRequestChunk regarding releasing its reference count (i.e. calling {@link
* io.netty.util.ReferenceCountUtil#release(Object)} and passing in initialRequestChunk). If the returned
* CompletableFuture is successful it means initialRequestChunk's reference count will already be reduced by one
* relative to when this method was called because it will have been passed to a successful {@link
* ChannelHandlerContext#writeAndFlush(Object)} method call.
* <p/>
* Long story short - assume initialRequestChunk is an object with a reference count of x:
* <ul>
* <li>
* If the returned CompletableFuture is successful, then when it completes successfully
* initialRequestChunk's reference count will be x - 1
* </li>
* <li>
* If the returned CompletableFuture is *NOT* successful, then when it completes initialRequestChunk's
* reference count will still be x
* </li>
* </ul>
*/
public CompletableFuture<StreamingChannel> streamDownstreamCall(String downstreamHost, int downstreamPort, HttpRequest initialRequestChunk, boolean isSecureHttpsCall, boolean relaxedHttpsValidation, StreamingCallback callback, long downstreamCallTimeoutMillis, ChannelHandlerContext ctx) {
CompletableFuture<StreamingChannel> streamingChannel = new CompletableFuture<>();
initialRequestChunk.headers().set(HttpHeaders.Names.HOST, downstreamHost);
boolean performSubSpanAroundDownstreamCalls = true;
ObjectHolder<Long> beforeConnectionStartTimeNanos = new ObjectHolder<>();
beforeConnectionStartTimeNanos.heldObject = System.nanoTime();
// Create a connection to the downstream server.
ChannelPool pool = getPooledChannelFuture(downstreamHost, downstreamPort);
Future<Channel> channelFuture = pool.acquire();
// Add a listener that kicks off the downstream call once the connection is completed.
channelFuture.addListener(future -> {
Pair<Deque<Span>, Map<String, String>> originalThreadInfo = null;
try {
originalThreadInfo = linkTracingAndMdcToCurrentThread(ctx);
if (!future.isSuccess()) {
try {
streamingChannel.completeExceptionally(new WrapperException("Unable to connect to downstream host: " + downstreamHost, future.cause()));
} finally {
Channel ch = channelFuture.getNow();
if (ch != null) {
markChannelAsBroken(ch);
pool.release(ch);
}
}
return;
}
if (logger.isDebugEnabled()) {
logger.debug("CONNECTION SETUP TIME NANOS: {}", (System.nanoTime() - beforeConnectionStartTimeNanos.heldObject));
}
if (performSubSpanAroundDownstreamCalls) {
String spanName = getSubspanSpanName(initialRequestChunk.getMethod().name(), downstreamHost + ":" + downstreamPort + initialRequestChunk.getUri());
if (Tracer.getInstance().getCurrentSpan() == null) {
Tracer.getInstance().startRequestWithRootSpan(spanName);
} else {
Tracer.getInstance().startSubSpan(spanName, Span.SpanPurpose.CLIENT);
}
}
Deque<Span> distributedSpanStackToUse = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcContextToUse = MDC.getCopyOfContextMap();
Span spanForDownstreamCall = (distributedSpanStackToUse == null) ? null : distributedSpanStackToUse.peek();
if (spanForDownstreamCall != null) {
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.TRACE_SAMPLED, String.valueOf(spanForDownstreamCall.isSampleable()));
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.TRACE_ID, spanForDownstreamCall.getTraceId());
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.SPAN_ID, spanForDownstreamCall.getSpanId());
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.PARENT_SPAN_ID, spanForDownstreamCall.getParentSpanId());
setHeaderIfValueNotNull(initialRequestChunk, TraceHeaders.SPAN_NAME, spanForDownstreamCall.getSpanName());
}
Channel ch = channelFuture.getNow();
if (logger.isDebugEnabled())
logger.debug("Channel ID of the Channel pulled from the pool: {}", ch.toString());
ch.eventLoop().execute(runnableWithTracingAndMdc(() -> {
BiConsumer<String, Throwable> prepChannelErrorHandler = (errorMessage, cause) -> {
try {
streamingChannel.completeExceptionally(new WrapperException(errorMessage, cause));
} finally {
markChannelAsBroken(ch);
pool.release(ch);
}
};
try {
ObjectHolder<Boolean> callActiveHolder = new ObjectHolder<>();
callActiveHolder.heldObject = true;
ObjectHolder<Boolean> lastChunkSentDownstreamHolder = new ObjectHolder<>();
lastChunkSentDownstreamHolder.heldObject = false;
prepChannelForDownstreamCall(pool, ch, callback, distributedSpanStackToUse, mdcContextToUse, isSecureHttpsCall, relaxedHttpsValidation, performSubSpanAroundDownstreamCalls, downstreamCallTimeoutMillis, callActiveHolder, lastChunkSentDownstreamHolder);
logInitialRequestChunk(initialRequestChunk, downstreamHost, downstreamPort);
ChannelFuture writeFuture = ch.writeAndFlush(initialRequestChunk);
writeFuture.addListener(completedWriteFuture -> {
if (completedWriteFuture.isSuccess())
streamingChannel.complete(new StreamingChannel(ch, pool, callActiveHolder, lastChunkSentDownstreamHolder, distributedSpanStackToUse, mdcContextToUse));
else {
prepChannelErrorHandler.accept("Writing the first HttpRequest chunk to the downstream service failed.", completedWriteFuture.cause());
return;
}
});
} catch (SSLException | NoSuchAlgorithmException | KeyStoreException ex) {
prepChannelErrorHandler.accept("Error setting up SSL context for downstream call", ex);
return;
} catch (Throwable t) {
prepChannelErrorHandler.accept("An unexpected error occurred while prepping the channel pipeline for the downstream call", t);
return;
}
}, ctx));
} catch (Throwable ex) {
try {
String errorMsg = "Error occurred attempting to send first chunk (headers/etc) downstream";
Exception errorToFire = new WrapperException(errorMsg, ex);
logger.warn(errorMsg, errorToFire);
streamingChannel.completeExceptionally(errorToFire);
} finally {
Channel ch = channelFuture.getNow();
if (ch != null) {
markChannelAsBroken(ch);
pool.release(ch);
}
}
} finally {
unlinkTracingAndMdcFromCurrentThread(originalThreadInfo);
}
});
return streamingChannel;
}
Aggregations