spring-data-redis icon indicating copy to clipboard operation
spring-data-redis copied to clipboard

Support ReactiveCrudRepository for Spring Data Redis Reactive [DATAREDIS-831]

Open spring-projects-issues opened this issue 7 years ago • 8 comments
trafficstars

Michael Gmeiner opened DATAREDIS-831 and commented

I do not find any support of using the RedisRepository feature with ReactiveCrudRepository. 

For example the following using:

@Repository
interface BookRepo : ReactiveCrudRepository<Book, String>

with @EnableRedisRepositories annotation present

and using default auto configuration from: spring-boot-starter-data-redis-reactive

I always get following error: 

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [my.package.hash.Book] to type [reactor.core.publisher.Mono<?>]org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [my.package.hash.Book] to type [reactor.core.publisher.Mono<?>] at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321) at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194) at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174) at org.springframework.data.repository.util.ReactiveWrapperConverters.toWrapper(ReactiveWrapperConverters.java:197) at org.springframework.data.repository.core.support.QueryExecutionResultHandler.postProcessInvocationResult(QueryExecutionResultHandler.java:126) at org.springframework.data.repository.core.support.QueryExecutionResultHandler.postProcessInvocationResult(QueryExecutionResultHandler.java:72) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:580) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.data.repository.core.support.MethodInvocationValidator.invoke(MethodInvocationValidator.java:99) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy104.findById(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy104.findById(Unknown Source)

when calling for example:

bookRepo.findById("harrypotter").subscribe { println(it) }

Am i doing something wrong or is it just not implemented yet as i do not find any documentation or examples on that? 


Affects: 2.0.7 (Kay SR7)

Issue Links:

  • DATAREDIS-796 Does Spring Data Redis have plans to support Reactive Repositories? ("duplicates")

7 votes, 8 watchers

spring-projects-issues avatar May 09 '18 15:05 spring-projects-issues

Mark Paluch commented

Hey Michael Gmeiner,

we currently don't have plans to support reactive Redis repositories. There's a rationale in DATAREDIS-796.

Unless we get a significant number of users asking for reactive Redis repositories, we'd provide only synchronous/imperative repository support.

I'll leave this one open so interested users can leave their vote

spring-projects-issues avatar May 09 '18 16:05 spring-projects-issues

Michael Gmeiner commented

Thanks for the quick reply. That's a real pity. In my company we take a lot of use of redis hashes and the RedisRepository are a great feature which simplifies that a lot. So sad that we cannot take full advantage of reactive redis. 

Can you maybe update the documentation and state that redis repositories are currently not supported and also describe the reason for that?

spring-projects-issues avatar May 09 '18 16:05 spring-projects-issues

Mark Paluch commented

We're using Jira for that. Keeping the current state of affairs and reasons for our decisions in the docs would make the docs a magnet for change and really not usable because of the reasoning noise. In general: If it's not documented, it's not there

spring-projects-issues avatar May 09 '18 16:05 spring-projects-issues

Michael Gmeiner commented

Yes i understand you and i also understand the effort behind it but the documentation confuses here. It seems that it is supported because you can use the interface and there's no info that it will no work or is not implemented for reactive redis. Also you do not get a proper exception.. I think people that are using spring-data-redis because of the nice RedisHash feature will run into that problem again when trying to switch to a reactive programming manner

spring-projects-issues avatar May 09 '18 17:05 spring-projects-issues

Mark Paluch commented

In the meantime, you can use ObjectHashMapper to map between objects and hashes without being bound to a particular execution method

spring-projects-issues avatar May 11 '18 07:05 spring-projects-issues

@markpollack @mp911de (not sure which username is correct)

Among other things, @EnableRedisRepositories has attributes to turn on keyspace notification events listener. While I've managed to get around the absence of reactive Redis repos, is there a way to enable the keyspace notifications from code (not the listener but the feature)? If you point me to the code that does this in Spring Data Redis, that'll be very helpful.

This is my reactive repo impl.

@Repository
class UuidRepository(
    private val redisTemplate: ReactiveRedisTemplate<String, Uuid>
) {
    private val reactiveValueOps = redisTemplate.opsForValue()
    suspend fun save(uuid: Uuid, ttl: Duration = Duration.ofSeconds(1L)): Boolean {
        return reactiveValueOps.setAndAwait(uuid.userId, uuid, ttl)
    }

    suspend fun findById(userId: String): Uuid? = reactiveValueOps.getAndAwait(userId)
}

asarkar avatar Jul 23 '21 06:07 asarkar

Any update to support Reactive repository?

hantsy avatar Dec 20 '21 08:12 hantsy

@mp911de commented almost 4 years ago:

we currently don't have plans to support reactive Redis repositories

Did plans regarding this evolved/changed during these (almost) 4 years?

Thanks in advance for the update on this

juliojgd avatar Apr 09 '22 08:04 juliojgd

Any update on the roadmap please?

Richardmbs12 avatar Feb 24 '23 16:02 Richardmbs12

Thanks for asking. With the recent development around Virtual Threads, the number of reasons to have reactive Redis repositories is shrinking to zero. Without Virtual Threads, scalability and non-blocking usage of repositories would have been a reason for a reactive API.

The implementation behind Redis Repositories bears a lot of complexity, requiring us to implement many infrastructure components and abstractions to avoid code duplications. Given Virtual Threads on the horizon, we rather recommend using imperative repositories running on Virtual Threads.

Repositories do not contribute any of the other reactive traits, such as backpressure or streaming support, that might be of interest in a reactive application arrangement.

Therefore, we decided to not implement this feature request.

mp911de avatar Mar 07 '23 07:03 mp911de