Search in sources :

Example 1 with FutureListener

use of io.netty.util.concurrent.FutureListener in project redisson by redisson.

the class BaseRemoteService method async.

private <T> T async(final Class<T> remoteInterface, final RemoteInvocationOptions options, final Class<?> syncInterface) {
    // local copy of the options, to prevent mutation
    final RemoteInvocationOptions optionsCopy = new RemoteInvocationOptions(options);
    final String toString = getClass().getSimpleName() + "-" + remoteInterface.getSimpleName() + "-proxy-" + generateRequestId();
    InvocationHandler handler = new InvocationHandler() {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("toString")) {
                return toString;
            } else if (method.getName().equals("equals")) {
                return proxy == args[0];
            } else if (method.getName().equals("hashCode")) {
                return toString.hashCode();
            }
            if (!optionsCopy.isResultExpected() && !(method.getReturnType().equals(Void.class) || method.getReturnType().equals(Void.TYPE) || method.getReturnType().equals(RFuture.class))) {
                throw new IllegalArgumentException("The noResult option only supports void return value");
            }
            final String requestId = generateRequestId();
            final String requestQueueName = getRequestQueueName(syncInterface);
            final String responseName = getResponseQueueName(syncInterface, requestId);
            final String ackName = getAckName(syncInterface, requestId);
            final RBlockingQueue<RemoteServiceRequest> requestQueue = redisson.getBlockingQueue(requestQueueName, getCodec());
            final RemoteServiceRequest request = new RemoteServiceRequest(requestId, method.getName(), getMethodSignatures(method), args, optionsCopy, System.currentTimeMillis());
            final RemotePromise<Object> result = new RemotePromise<Object>(commandExecutor.getConnectionManager().newPromise()) {

                @Override
                public boolean cancel(boolean mayInterruptIfRunning) {
                    if (isCancelled()) {
                        return true;
                    }
                    if (isDone()) {
                        return false;
                    }
                    if (optionsCopy.isAckExpected()) {
                        RFuture<Boolean> future = 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('lrem', KEYS[3], 1, ARGV[1]);" + "redis.call('pexpire', KEYS[2], ARGV[2]);" + "return 1;" + "end;" + "return 0;", Arrays.<Object>asList(ackName, responseName, requestQueueName), encode(request), request.getOptions().getAckTimeoutInMillis());
                        boolean ackNotSent = commandExecutor.get(future);
                        if (ackNotSent) {
                            super.cancel(mayInterruptIfRunning);
                            return true;
                        }
                        return cancel(syncInterface, requestId, request, mayInterruptIfRunning);
                    }
                    boolean removed = remove(requestQueue, request);
                    if (removed) {
                        super.cancel(mayInterruptIfRunning);
                        return true;
                    }
                    return cancel(syncInterface, requestId, request, mayInterruptIfRunning);
                }

                private boolean cancel(Class<?> remoteInterface, String requestId, RemoteServiceRequest request, boolean mayInterruptIfRunning) {
                    if (isCancelled()) {
                        return true;
                    }
                    if (isDone()) {
                        return false;
                    }
                    String canceRequestName = getCancelRequestQueueName(remoteInterface, requestId);
                    cancelExecution(optionsCopy, responseName, request, mayInterruptIfRunning, canceRequestName, this);
                    awaitUninterruptibly(60, TimeUnit.SECONDS);
                    return isCancelled();
                }
            };
            result.setRequestId(requestId);
            RFuture<Boolean> addFuture = addAsync(requestQueue, request, result);
            addFuture.addListener(new FutureListener<Boolean>() {

                @Override
                public void operationComplete(Future<Boolean> future) throws Exception {
                    if (!future.isSuccess()) {
                        result.tryFailure(future.cause());
                        return;
                    }
                    if (optionsCopy.isAckExpected()) {
                        final RBlockingQueue<RemoteServiceAck> responseQueue = redisson.getBlockingQueue(responseName, getCodec());
                        RFuture<RemoteServiceAck> ackFuture = responseQueue.pollAsync(optionsCopy.getAckTimeoutInMillis(), TimeUnit.MILLISECONDS);
                        ackFuture.addListener(new FutureListener<RemoteServiceAck>() {

                            @Override
                            public void operationComplete(Future<RemoteServiceAck> future) throws Exception {
                                if (!future.isSuccess()) {
                                    result.tryFailure(future.cause());
                                    return;
                                }
                                RemoteServiceAck ack = future.getNow();
                                if (ack == null) {
                                    RFuture<RemoteServiceAck> ackFutureAttempt = tryPollAckAgainAsync(optionsCopy, responseQueue, ackName);
                                    ackFutureAttempt.addListener(new FutureListener<RemoteServiceAck>() {

                                        @Override
                                        public void operationComplete(Future<RemoteServiceAck> future) throws Exception {
                                            if (!future.isSuccess()) {
                                                result.tryFailure(future.cause());
                                                return;
                                            }
                                            if (future.getNow() == null) {
                                                Exception ex = new RemoteServiceAckTimeoutException("No ACK response after " + optionsCopy.getAckTimeoutInMillis() + "ms for request: " + request);
                                                result.tryFailure(ex);
                                                return;
                                            }
                                            awaitResultAsync(optionsCopy, result, request, responseName, ackName);
                                        }
                                    });
                                } else {
                                    awaitResultAsync(optionsCopy, result, request, responseName);
                                }
                            }
                        });
                    } else {
                        awaitResultAsync(optionsCopy, result, request, responseName);
                    }
                }
            });
            return result;
        }
    };
    return (T) Proxy.newProxyInstance(remoteInterface.getClassLoader(), new Class[] { remoteInterface }, handler);
}
Also used : RBlockingQueue(org.redisson.api.RBlockingQueue) RemoteServiceAck(org.redisson.remote.RemoteServiceAck) FutureListener(io.netty.util.concurrent.FutureListener) Method(java.lang.reflect.Method) RFuture(org.redisson.api.RFuture) InvocationHandler(java.lang.reflect.InvocationHandler) RemoteServiceTimeoutException(org.redisson.remote.RemoteServiceTimeoutException) IOException(java.io.IOException) RemoteServiceAckTimeoutException(org.redisson.remote.RemoteServiceAckTimeoutException) RemoteInvocationOptions(org.redisson.api.RemoteInvocationOptions) RemoteServiceRequest(org.redisson.remote.RemoteServiceRequest) RFuture(org.redisson.api.RFuture) Future(io.netty.util.concurrent.Future) RemoteServiceAckTimeoutException(org.redisson.remote.RemoteServiceAckTimeoutException) RemotePromise(org.redisson.executor.RemotePromise)

Example 2 with FutureListener

use of io.netty.util.concurrent.FutureListener in project redisson by redisson.

the class RedisNodes method pingAll.

@Override
public boolean pingAll() {
    List<RedisClientEntry> clients = new ArrayList<RedisClientEntry>(connectionManager.getClients());
    final Map<RedisConnection, RFuture<String>> result = new ConcurrentHashMap<RedisConnection, RFuture<String>>(clients.size());
    final CountDownLatch latch = new CountDownLatch(clients.size());
    for (RedisClientEntry entry : clients) {
        RFuture<RedisConnection> f = entry.getClient().connectAsync();
        f.addListener(new FutureListener<RedisConnection>() {

            @Override
            public void operationComplete(Future<RedisConnection> future) throws Exception {
                if (future.isSuccess()) {
                    final RedisConnection c = future.getNow();
                    RPromise<RedisConnection> connectionFuture = connectionManager.newPromise();
                    connectionManager.getConnectListener().onConnect(connectionFuture, c, null, connectionManager.getConfig());
                    connectionFuture.addListener(new FutureListener<RedisConnection>() {

                        @Override
                        public void operationComplete(Future<RedisConnection> future) throws Exception {
                            RFuture<String> r = c.async(connectionManager.getConfig().getPingTimeout(), RedisCommands.PING);
                            result.put(c, r);
                            latch.countDown();
                        }
                    });
                } else {
                    latch.countDown();
                }
            }
        });
    }
    long time = System.currentTimeMillis();
    try {
        latch.await();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    if (System.currentTimeMillis() - time >= connectionManager.getConfig().getConnectTimeout()) {
        for (Entry<RedisConnection, RFuture<String>> entry : result.entrySet()) {
            entry.getKey().closeAsync();
        }
        return false;
    }
    time = System.currentTimeMillis();
    boolean res = true;
    for (Entry<RedisConnection, RFuture<String>> entry : result.entrySet()) {
        RFuture<String> f = entry.getValue();
        f.awaitUninterruptibly();
        if (!"PONG".equals(f.getNow())) {
            res = false;
        }
        entry.getKey().closeAsync();
    }
    // true and no futures missed during client connection
    return res && result.size() == clients.size();
}
Also used : FutureListener(io.netty.util.concurrent.FutureListener) RPromise(org.redisson.misc.RPromise) ArrayList(java.util.ArrayList) RFuture(org.redisson.api.RFuture) CountDownLatch(java.util.concurrent.CountDownLatch) RFuture(org.redisson.api.RFuture) Future(io.netty.util.concurrent.Future) RedisClientEntry(org.redisson.connection.RedisClientEntry) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) RedisConnection(org.redisson.client.RedisConnection)

Example 3 with FutureListener

use of io.netty.util.concurrent.FutureListener 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);
                        }
                    }
                }
            }
        }

        ;
    });
}
Also used : FutureListener(io.netty.util.concurrent.FutureListener) Timeout(io.netty.util.Timeout) AtomicReference(java.util.concurrent.atomic.AtomicReference) RFuture(org.redisson.api.RFuture) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) TimerTask(io.netty.util.TimerTask) RFuture(org.redisson.api.RFuture) Future(io.netty.util.concurrent.Future)

Example 4 with FutureListener

use of io.netty.util.concurrent.FutureListener 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);
                        }
                    }
                }
            }
        }

        ;
    });
}
Also used : FutureListener(io.netty.util.concurrent.FutureListener) Timeout(io.netty.util.Timeout) AtomicReference(java.util.concurrent.atomic.AtomicReference) RFuture(org.redisson.api.RFuture) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) TimerTask(io.netty.util.TimerTask) RFuture(org.redisson.api.RFuture) Future(io.netty.util.concurrent.Future)

Example 5 with FutureListener

use of io.netty.util.concurrent.FutureListener 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);
            }
        }
    });
}
Also used : FutureListener(io.netty.util.concurrent.FutureListener) RFuture(org.redisson.api.RFuture) RemoteServiceRequest(org.redisson.remote.RemoteServiceRequest) RFuture(org.redisson.api.RFuture) Future(io.netty.util.concurrent.Future) RemoteServiceAck(org.redisson.remote.RemoteServiceAck)

Aggregations

FutureListener (io.netty.util.concurrent.FutureListener)29 Future (io.netty.util.concurrent.Future)26 RFuture (org.redisson.api.RFuture)20 ChannelFuture (io.netty.channel.ChannelFuture)10 ChannelFutureListener (io.netty.channel.ChannelFutureListener)10 AtomicReference (java.util.concurrent.atomic.AtomicReference)7 Timeout (io.netty.util.Timeout)6 TimerTask (io.netty.util.TimerTask)6 ArrayList (java.util.ArrayList)6 CountDownLatch (java.util.concurrent.CountDownLatch)6 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)6 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)6 RedisConnection (org.redisson.client.RedisConnection)6 Channel (io.netty.channel.Channel)4 NioEventLoopGroup (io.netty.channel.nio.NioEventLoopGroup)4 ScheduledFuture (io.netty.util.concurrent.ScheduledFuture)4 Test (org.junit.jupiter.api.Test)4 RedisConnectionException (org.redisson.client.RedisConnectionException)4 RedisException (org.redisson.client.RedisException)4 NodeSource (org.redisson.connection.NodeSource)4