Search in sources :

Example 1 with CacheException

use of io.quarkus.cache.CacheException in project quarkus by quarkusio.

the class CacheResultInterceptor method intercept.

@AroundInvoke
public Object intercept(InvocationContext invocationContext) throws Throwable {
    /*
         * io.smallrye.mutiny.Multi values are never cached.
         * There's already a WARN log entry at build time so we don't need to log anything at run time.
         */
    if (Multi.class.isAssignableFrom(invocationContext.getMethod().getReturnType())) {
        return invocationContext.proceed();
    }
    CacheInterceptionContext<CacheResult> interceptionContext = getInterceptionContext(invocationContext, CacheResult.class, true);
    if (interceptionContext.getInterceptorBindings().isEmpty()) {
        // This should never happen.
        LOGGER.warn(INTERCEPTOR_BINDING_ERROR_MSG);
        return invocationContext.proceed();
    }
    CacheResult binding = interceptionContext.getInterceptorBindings().get(0);
    AbstractCache cache = (AbstractCache) cacheManager.getCache(binding.cacheName()).get();
    Object key = getCacheKey(cache, interceptionContext.getCacheKeyParameterPositions(), invocationContext.getParameters());
    LOGGER.debugf("Loading entry with key [%s] from cache [%s]", key, binding.cacheName());
    try {
        ReturnType returnType = determineReturnType(invocationContext.getMethod().getReturnType());
        if (returnType != ReturnType.NonAsync) {
            Uni<Object> cacheValue = cache.get(key, new Function<Object, Object>() {

                @Override
                public Object apply(Object k) {
                    LOGGER.debugf("Adding %s entry with key [%s] into cache [%s]", UnresolvedUniValue.class.getSimpleName(), key, binding.cacheName());
                    return UnresolvedUniValue.INSTANCE;
                }
            }).onItem().transformToUni(new Function<Object, Uni<?>>() {

                @Override
                public Uni<?> apply(Object value) {
                    if (value == UnresolvedUniValue.INSTANCE) {
                        try {
                            return asyncInvocationResultToUni(invocationContext.proceed(), returnType).call(new Function<Object, Uni<?>>() {

                                @Override
                                public Uni<?> apply(Object emittedValue) {
                                    return cache.replaceUniValue(key, emittedValue);
                                }
                            });
                        } catch (CacheException e) {
                            throw e;
                        } catch (Exception e) {
                            throw new CacheException(e);
                        }
                    } else {
                        return Uni.createFrom().item(value);
                    }
                }
            });
            if (binding.lockTimeout() <= 0) {
                return createAsyncResult(cacheValue, returnType);
            }
            cacheValue = cacheValue.ifNoItem().after(Duration.ofMillis(binding.lockTimeout())).recoverWithUni(new Supplier<Uni<?>>() {

                @Override
                public Uni<?> get() {
                    try {
                        return asyncInvocationResultToUni(invocationContext.proceed(), returnType);
                    } catch (CacheException e) {
                        throw e;
                    } catch (Exception e) {
                        throw new CacheException(e);
                    }
                }
            });
            return createAsyncResult(cacheValue, returnType);
        } else {
            Uni<Object> cacheValue = cache.get(key, new Function<Object, Object>() {

                @Override
                public Object apply(Object k) {
                    try {
                        LOGGER.debugf("Adding entry with key [%s] into cache [%s]", key, binding.cacheName());
                        return invocationContext.proceed();
                    } catch (CacheException e) {
                        throw e;
                    } catch (Throwable e) {
                        throw new CacheException(e);
                    }
                }
            });
            Object value;
            if (binding.lockTimeout() <= 0) {
                value = cacheValue.await().indefinitely();
            } else {
                try {
                    /*
                         * If the current thread started the cache value computation, then the computation is already finished
                         * since
                         * it was done synchronously and the following call will never time out.
                         */
                    value = cacheValue.await().atMost(Duration.ofMillis(binding.lockTimeout()));
                } catch (TimeoutException e) {
                    // TODO: Add statistics here to monitor the timeout.
                    return invocationContext.proceed();
                }
            }
            return value;
        }
    } catch (CacheException e) {
        if (e.getCause() != null) {
            throw e.getCause();
        } else {
            throw e;
        }
    }
}
Also used : CacheException(io.quarkus.cache.CacheException) TimeoutException(io.smallrye.mutiny.TimeoutException) CacheException(io.quarkus.cache.CacheException) Uni(io.smallrye.mutiny.Uni) Function(java.util.function.Function) CacheResult(io.quarkus.cache.CacheResult) Supplier(java.util.function.Supplier) TimeoutException(io.smallrye.mutiny.TimeoutException) AroundInvoke(javax.interceptor.AroundInvoke)

Aggregations

CacheException (io.quarkus.cache.CacheException)1 CacheResult (io.quarkus.cache.CacheResult)1 TimeoutException (io.smallrye.mutiny.TimeoutException)1 Uni (io.smallrye.mutiny.Uni)1 Function (java.util.function.Function)1 Supplier (java.util.function.Supplier)1 AroundInvoke (javax.interceptor.AroundInvoke)1