question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

"Exception thrown during asynchronous load" when using quarkus-cache and quarkus-hibernate-validator

See original GitHub issue

Describe the bug When using service validation on a method and also use caching on that service method an exception is written to the log.

Expected behavior No exception is written to the log.

Actual behavior Something like this exception is written to the log:

WARNING: Exception thrown during asynchronous load
java.util.concurrent.CompletionException: javax.validation.ConstraintViolationException: 1 constraint violation(s) occurred during method validation.
Constructor or Method: public java.lang.String ...Service.doService(ServiceRequest)
Argument values: [...ServiceRequest@7a0f43dc]
Constraint violations: 
 (1) Kind: PROPERTY
 message: darf nicht null sein
 root bean: ...Service_Subclass@15ec2ac4
 property path: doService.arg0.text
 constraint: @javax.validation.constraints.NotNull(message="{javax.validation.constraints.NotNull.message}", payload={}, groups={})
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
	at io.smallrye.context.SmallRyeThreadContext$ContextualRunnable.run(SmallRyeThreadContext.java:56)
	at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)

	at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2046)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1578)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
	at java.base/java.lang.Thread.run(Thread.java:834)
	at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: javax.validation.ConstraintViolationException: 1 constraint violation(s) occurred during method validation.
Constructor or Method: public java.lang.String Service.doService(...ServiceRequest)
Argument values: [...ServiceRequest@7a0f43dc]
Constraint violations: 
 (1) Kind: PROPERTY
 message: darf nicht null sein
 root bean: Service_Subclass@15ec2ac4
 property path: service.arg0.text
 constraint: @javax.validation.constraints.NotNull(message="{javax.validation.constraints.NotNull.message}", payload={}, groups={})
	at io.quarkus.hibernate.validator.runtime.interceptor.AbstractMethodValidationInterceptor.validateMethodInvocation(AbstractMethodValidationInterceptor.java:65)
	at io.quarkus.hibernate.validator.runtime.interceptor.MethodValidationInterceptor.validateMethodInvocation(MethodValidationInterceptor.java:17)
	at io.quarkus.hibernate.validator.runtime.interceptor.MethodValidationInterceptor_Bean.intercept(MethodValidationInterceptor_Bean.zig:340)
	at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
	at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:50)
	at io.quarkus.cache.runtime.CacheResultInterceptor.lambda$intercept$0(CacheResultInterceptor.java:27)
	at io.quarkus.cache.runtime.caffeine.CaffeineCache$MappingSupplier.get(CaffeineCache.java:136)
	at io.quarkus.cache.runtime.caffeine.CaffeineCache.lambda$get$0(CaffeineCache.java:58)
	at com.github.benmanes.caffeine.cache.LocalAsyncCache.lambda$get$0(LocalAsyncCache.java:77)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
	... 9 more

To Reproduce In the pom.xml add:

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-cache</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-hibernate-validator</artifactId>
    </dependency>

Create a service like this:

@ApplicationScoped
public class Service {
  @CacheResult(cacheName = "cache")
  public String doService(@Valid ServiceRequest request) {
    // do something important
  }
}

Create a ServiceRequest POJO with validation annotations:

public class ServiceRequest{
  @NotNull
  private String text;
  // getters / setters
}

Invoke the service method from a QuarkusTest or REST service (with text = null), then the error will appear. It doesn’t if I remove the cache annotation.

Environment (please complete the following information):

  • Output of uname -a or ver: Microsoft Windows [Version 10.0.17763.1282]
  • Output of java -version: java version “11.0.7” 2020-04-14 LTS
  • GraalVM version (if different from Java):
  • Quarkus version or git rev: 1.6.1.Final
  • Build tool (ie. output of mvnw --version or gradlew --version): Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
ben-manescommented, Aug 23, 2020

It looks like Quarkus has its own configuration file for logging (docs). You could simply specify a default log level in your templates that suppress Caffeine’s logging. If the majority of your users setup based on a common init script, it would become an implicit default.

A code workaround would be to translate the error into a success with an error’d value. Instead of the future being exceptional, it would hold a result object that was marked as a failure. The cache would consider it a successful load, while the handler could translate into a user-facing future. As the result would be cached, you would have to include an exceptional handler to remove the entry explicitly (safest by using asMap.remove(key, oldValue)).

From Caffeine’s perspective it is designed as a data structure (like any other Map) so we log minimally. Yet application developers very frequently struggle with asynchronous logic and do not consider failures. Unlike synchronous code where uncaught exceptions arrive at the thread’s defaultUncaughtExceptionHandler to be logged, the failure of a CompletableFuture is a stateful result. When chaining only on the happy path (then without an exceptionally block), the error is silently swallowed and in Caffeine that entry is removed. The lack of an exception handler may result in hard to find bugs as the developer was not guided by the programming model nor libraries to consider failures. That causes frustration, rightfully blames the tooling, so this logging helps uncover the mistake to provide a more pleasant experience. We responded to user complaints and, as logging is trivial to disable, I think it’s reasonable for Caffeine to warn on.

0reactions
ben-manescommented, Aug 24, 2020

It isn’t necessary, but a nice practice to avoid race conditions. If you use AsyncCache.asMap() then the value is the cached future. The reference equality check ensures that a concurrent removal & add doesn’t result in your callback accidentally removing the new entry. It’s a rare and minor race, but one you can squash if desired.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Application Data Caching - Quarkus
When the call to the remote throws an exception, the cache does not store the result, so that a subsequent call to callRemote()...
Read more >
Home of Quarkus Cheat-Sheet - GitHub Pages
Quarkus comes with a Maven archetype to scaffold a very simple starting project. ... overriding methods that override constraints should throw an exception....
Read more >
javax.validation.constraints.notnull maven dependency
quarkusio/quarkus"Exception thrown during asynchronous load" when using quarkus-cache and quarkus-hibernate-validator#11315. Created over 2 years ago.
Read more >
Using Quarkus Cache with Reactive and Mutiny correctly
The Subject is loaded from the cache, if available, by the cache key "subjectId". Migrating to Mutiny would look like this @CacheResult( ...
Read more >
quarkusio/quarkus 1.8.0.CR1 on GitHub - NewReleases.io
... "Exception thrown during asynchronous load" when using quarkus-cache and quarkus-hibernate-validator; #11312 - Avoid generated-sources clash with ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found