Search in sources :

Example 1 with RemoteInvocationOptions

use of org.redisson.api.RemoteInvocationOptions in project redisson by redisson.

the class RedissonRemoteServiceTest method testNoAckWithResultInvocationsAsync.

@Test
public void testNoAckWithResultInvocationsAsync() throws InterruptedException, ExecutionException {
    RedissonClient server = createInstance();
    RedissonClient client = createInstance();
    try {
        server.getRemoteService().register(RemoteInterface.class, new RemoteImpl());
        // no ack but an execution timeout of 1 second
        RemoteInvocationOptions options = RemoteInvocationOptions.defaults().noAck().expectResultWithin(1, TimeUnit.SECONDS);
        RemoteInterfaceAsync service = client.getRemoteService().get(RemoteInterfaceAsync.class, options);
        service.voidMethod("noAck", 100L).get();
        assertThat(service.resultMethod(21L).get()).isEqualTo(42);
        try {
            service.errorMethod().get();
            Assert.fail();
        } catch (Exception e) {
            assertThat(e.getCause().getMessage()).isEqualTo("Checking error throw");
        }
        try {
            service.errorMethodWithCause().get();
            Assert.fail();
        } catch (Exception e) {
            assertThat(e.getCause().getCause()).isInstanceOf(ArithmeticException.class);
            assertThat(e.getCause().getCause().getMessage()).isEqualTo("/ by zero");
        }
        try {
            service.timeoutMethod().get();
            Assert.fail("noAck option should still wait for the server to return a response and throw if the execution timeout is exceeded");
        } catch (Exception e) {
            assertThat(e.getCause()).isInstanceOf(RemoteServiceTimeoutException.class);
        }
    } finally {
        client.shutdown();
        server.shutdown();
    }
}
Also used : RedissonClient(org.redisson.api.RedissonClient) RemoteServiceTimeoutException(org.redisson.remote.RemoteServiceTimeoutException) RemoteServiceTimeoutException(org.redisson.remote.RemoteServiceTimeoutException) IOException(java.io.IOException) NotSerializableException(java.io.NotSerializableException) ExecutionException(java.util.concurrent.ExecutionException) RemoteServiceAckTimeoutException(org.redisson.remote.RemoteServiceAckTimeoutException) RemoteInvocationOptions(org.redisson.api.RemoteInvocationOptions) Test(org.junit.Test)

Example 2 with RemoteInvocationOptions

use of org.redisson.api.RemoteInvocationOptions in project redisson by redisson.

the class RedissonRemoteServiceTest method testAckWithoutResultInvocations.

@Test
public void testAckWithoutResultInvocations() throws InterruptedException {
    RedissonClient server = createInstance();
    RedissonClient client = createInstance();
    try {
        server.getRemoteService().register(RemoteInterface.class, new RemoteImpl());
        // fire and forget with an ack timeout of 1 sec
        RemoteInvocationOptions options = RemoteInvocationOptions.defaults().expectAckWithin(1, TimeUnit.SECONDS).noResult();
        RemoteInterface service = client.getRemoteService().get(RemoteInterface.class, options);
        service.voidMethod("noResult", 100L);
        try {
            service.resultMethod(100L);
            Assert.fail();
        } catch (Exception e) {
            assertThat(e).isInstanceOf(IllegalArgumentException.class);
        }
        try {
            service.errorMethod();
        } catch (IOException e) {
            Assert.fail("noResult option should not throw server side exception");
        }
        try {
            service.errorMethodWithCause();
        } catch (Exception e) {
            Assert.fail("noResult option should not throw server side exception");
        }
        long time = System.currentTimeMillis();
        service.timeoutMethod();
        time = System.currentTimeMillis() - time;
        assertThat(time).describedAs("noResult option should not wait for the server to return a response").isLessThan(2000);
        try {
            service.timeoutMethod();
            Assert.fail("noResult option should still wait for the server to ack the request and throw if the ack timeout is exceeded");
        } catch (Exception e) {
            assertThat(e).isInstanceOf(RemoteServiceAckTimeoutException.class);
        }
    } finally {
        client.shutdown();
        server.shutdown();
    }
}
Also used : RedissonClient(org.redisson.api.RedissonClient) RemoteServiceAckTimeoutException(org.redisson.remote.RemoteServiceAckTimeoutException) IOException(java.io.IOException) RemoteServiceTimeoutException(org.redisson.remote.RemoteServiceTimeoutException) IOException(java.io.IOException) NotSerializableException(java.io.NotSerializableException) ExecutionException(java.util.concurrent.ExecutionException) RemoteServiceAckTimeoutException(org.redisson.remote.RemoteServiceAckTimeoutException) RemoteInvocationOptions(org.redisson.api.RemoteInvocationOptions) Test(org.junit.Test)

Example 3 with RemoteInvocationOptions

use of org.redisson.api.RemoteInvocationOptions in project redisson by redisson.

the class RedissonRemoteServiceTest method testNoAckWithResultInvocations.

@Test
public void testNoAckWithResultInvocations() throws InterruptedException {
    RedissonClient server = createInstance();
    RedissonClient client = createInstance();
    try {
        server.getRemoteService().register(RemoteInterface.class, new RemoteImpl());
        // no ack but an execution timeout of 1 second
        RemoteInvocationOptions options = RemoteInvocationOptions.defaults().noAck().expectResultWithin(1, TimeUnit.SECONDS);
        RemoteInterface service = client.getRemoteService().get(RemoteInterface.class, options);
        service.voidMethod("noAck", 100L);
        assertThat(service.resultMethod(21L)).isEqualTo(42);
        try {
            service.errorMethod();
            Assert.fail();
        } catch (IOException e) {
            assertThat(e.getMessage()).isEqualTo("Checking error throw");
        }
        try {
            service.errorMethodWithCause();
            Assert.fail();
        } catch (Exception e) {
            assertThat(e.getCause()).isInstanceOf(ArithmeticException.class);
            assertThat(e.getCause().getMessage()).isEqualTo("/ by zero");
        }
        try {
            service.timeoutMethod();
            Assert.fail("noAck option should still wait for the server to return a response and throw if the execution timeout is exceeded");
        } catch (Exception e) {
            assertThat(e).isInstanceOf(RemoteServiceTimeoutException.class);
        }
    } finally {
        client.shutdown();
        server.shutdown();
    }
}
Also used : RedissonClient(org.redisson.api.RedissonClient) RemoteServiceTimeoutException(org.redisson.remote.RemoteServiceTimeoutException) IOException(java.io.IOException) RemoteServiceTimeoutException(org.redisson.remote.RemoteServiceTimeoutException) IOException(java.io.IOException) NotSerializableException(java.io.NotSerializableException) ExecutionException(java.util.concurrent.ExecutionException) RemoteServiceAckTimeoutException(org.redisson.remote.RemoteServiceAckTimeoutException) RemoteInvocationOptions(org.redisson.api.RemoteInvocationOptions) Test(org.junit.Test)

Example 4 with RemoteInvocationOptions

use of org.redisson.api.RemoteInvocationOptions 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 5 with RemoteInvocationOptions

use of org.redisson.api.RemoteInvocationOptions in project redisson by redisson.

the class BaseRemoteService method cancelExecution.

private void cancelExecution(RemoteInvocationOptions optionsCopy, String responseName, RemoteServiceRequest request, boolean mayInterruptIfRunning, String canceRequestName, RemotePromise<Object> remotePromise) {
    RBlockingQueue<RemoteServiceCancelRequest> cancelRequestQueue = redisson.getBlockingQueue(canceRequestName, getCodec());
    cancelRequestQueue.putAsync(new RemoteServiceCancelRequest(mayInterruptIfRunning));
    cancelRequestQueue.expireAsync(60, TimeUnit.SECONDS);
    // subscribe for async result if it's not expected before
    if (!optionsCopy.isResultExpected()) {
        RemoteInvocationOptions options = new RemoteInvocationOptions(optionsCopy);
        options.expectResultWithin(60, TimeUnit.SECONDS);
        awaitResultAsync(options, remotePromise, request, responseName);
    }
}
Also used : RemoteServiceCancelRequest(org.redisson.remote.RemoteServiceCancelRequest) RemoteInvocationOptions(org.redisson.api.RemoteInvocationOptions)

Aggregations

RemoteInvocationOptions (org.redisson.api.RemoteInvocationOptions)7 RemoteServiceAckTimeoutException (org.redisson.remote.RemoteServiceAckTimeoutException)6 RemoteServiceTimeoutException (org.redisson.remote.RemoteServiceTimeoutException)6 IOException (java.io.IOException)5 NotSerializableException (java.io.NotSerializableException)4 ExecutionException (java.util.concurrent.ExecutionException)4 Test (org.junit.Test)4 RedissonClient (org.redisson.api.RedissonClient)4 InvocationHandler (java.lang.reflect.InvocationHandler)2 Method (java.lang.reflect.Method)2 RemoteServiceAck (org.redisson.remote.RemoteServiceAck)2 RemoteServiceRequest (org.redisson.remote.RemoteServiceRequest)2 Future (io.netty.util.concurrent.Future)1 FutureListener (io.netty.util.concurrent.FutureListener)1 RBlockingQueue (org.redisson.api.RBlockingQueue)1 RFuture (org.redisson.api.RFuture)1 RemotePromise (org.redisson.executor.RemotePromise)1 RRemoteServiceResponse (org.redisson.remote.RRemoteServiceResponse)1 RemoteServiceCancelRequest (org.redisson.remote.RemoteServiceCancelRequest)1 RemoteServiceResponse (org.redisson.remote.RemoteServiceResponse)1