Marian Klühspies
Marian Klühspies

Reputation: 17617

Using Quarkus Cache with Reactive and Mutiny correctly

I'm trying to migrate my project to Quarkus Reactive with Hibernate Reactive Panache and I'm not sure how to deal with caching.

My original method looked like this

    @Transactional
    @CacheResult(cacheName = "subject-cache")
    public Subject getSubject(@CacheKey String subjectId) throws Exception {
        return subjectRepository.findByIdentifier(subjectId);
    }

The Subject is loaded from the cache, if available, by the cache key "subjectId".

Migrating to Mutiny would look like this

    @CacheResult(cacheName = "subject-cache")
    public Uni<Subject> getSubject(@CacheKey String subjectId) {
        return subjectRepository.findByIdentifier(subjectId);
    }

However, it can't be right to store the Uni object in the cache.

There is also the option to inject the cache as a bean, however, the fallback function does not support to return an Uni:

    @Inject
    @CacheName("subject-cache")
    Cache cache;


  //does not work, cache.get function requires return type Subject, not Uni<Subject>
  public Uni<Subject> getSubject(String subjectId) {
        return cache.get(subjectId, s -> subjectRepository.findByIdentifier(subjectId));
    }

  //This works, needs blocking call to repo, to return response wrapped in new Uni
  public Uni<Subject> getSubject(String subjectId) {
        return cache.get(subjectId, s -> subjectRepository.findByIdentifier(subjectId).await().indefinitely());
    }

Can the @CacheResult annotations be used with Uni / Multi and everything is handled under the hood correctly?

Upvotes: 5

Views: 2921

Answers (2)

Vinicius
Vinicius

Reputation: 1154

The problem with caching Unis is that depending on how this Uni is created, multiple subscriptions can trigger some code multiple times. To avoid this you have to memoize the Uni like this:

@CacheResult(cacheName = "subject-cache")
public Uni<Subject> getSubject(@CacheKey String subjectId) {
    return subjectRepository.findByIdentifier(subjectId)
        .memoize().indefinitely();
}

This will ensure that every subscription to the cached Uni will always return the same value (item or failure) without re-executing anything of the original Uni flow.

Upvotes: 1

Jan Martiška
Jan Martiška

Reputation: 1314

Your example with a @CacheResult on a method that returns Uni should actually work. The implementation will automatically "strip" the Uni type and only store the Subject in the cache.

Upvotes: 4

Related Questions