-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Terminate stream with error on null
values returned by RedisElementReader
for top-level elements
#2672
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all these changes and Javadoc edits look completely fine to me.
I'd be curious what @christophstrobl would have to say about this, though.
I'm a bit torn on this one, since the |
So what do we want to do here? Our serializer clearly allow for |
null
values from top-level Flux
and Mono
responsesnull
values returned by RedisElementReader
for top-level elements
null
values returned by RedisElementReader
for top-level elementsnull
values returned by RedisElementReader
for top-level elements
…tReader` for top-level elements. We now emit InvalidDataAccessApiUsageException when a RedisElementReader returns null in the context of a top-level stream to indicate invalid API usage although RedisElementReader.read can generally return null values if these are being collected in a container or value wrapper or parent complex object.
Consistent operations documentation wording.
23c6ecf
to
0b123d2
Compare
I rewrote this pull request to document the behavior in the context of top-level stream values. We also now terminate the stream in a controlled manner by emitting |
I am reviewing this PR now and I generally like the direction the changes took. However, I don't necessarily agree with this:
I think this is a significant change in the contract and behavior of SD Redis that will potentially and adversely affect the older GA'd branches in the Honestly, with regard to #2655, I really think this is a user problem and application concern more than it is a framework issue that needs to be addressed and handled by the framework. While these changes are an improvement overall (i.e. failing fast when Reactive streams are misused as the user has done in #2655, along with employing the Spring Framework DAO Exception Hierarchy (Javadoc)), it is also a clear change in the contract and behavior that diverges from the Reactive Streams specification, which is very clear on the matter (Rule 2.13) of I also agree with and reiterate @christophstrobl comments above, earlier. |
@@ -285,7 +288,8 @@ public Mono<V> rightPopAndLeftPush(K sourceKey, K destinationKey, Duration timeo | |||
Assert.isTrue(isZeroOrGreater1Second(timeout), "Duration must be either zero or greater or equal to 1 second"); | |||
|
|||
return createMono( | |||
connection -> connection.bRPopLPush(rawKey(sourceKey), rawKey(destinationKey), timeout).map(this::readValue)); | |||
connection -> connection.bRPopLPush(rawKey(sourceKey), rawKey(destinationKey), timeout) | |||
.map(this::readRequiredValue)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be .mapNotNull(..)
in this case given the Duration
parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous variant was mapNotNull
that effectively filters null
values turning RedisElementReader
into something that has an ability of filtering. That's why we chose to use readRequiredValue
throwing a proper exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This previous variant was .map(this::readValue)
, line 288.
I was thinking more along the lines of the rightPop(key, :Duration)
overloaded method above on line 262.
But, perhaps the choice of simply .map(this:readRequiredValue)
vs. .mapNotNull(this:readRequiredValue)
is due to the right pop
followed by left push
compound operation??
See spring-projects#2655 Original pull request: spring-projects#2672
See spring-projects#2655 Original pull request: spring-projects#2672
@@ -40,6 +39,7 @@ | |||
import org.springframework.data.redis.domain.geo.GeoReference.GeoMemberReference; | |||
import org.springframework.data.redis.domain.geo.GeoShape; | |||
import org.springframework.data.redis.serializer.RedisSerializationContext; | |||
import org.springframework.lang.Nullable; | |||
import org.springframework.util.Assert; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to me the geoDist(..)
methods in ReactiveGeoOperations
for the GEODIST
command variations should be protected in the case of returning null
.
While the arguments passed to the ReactiveGeoOperations.distance(..)
methods used in the computation of the geo distance calculation may not be null
, the member
argument may also not have been geocoded in Redis with the geoAdd(..)
command properly (which I think is a prerequisite based on the docs).
Therefore, in the case of a "missing" member (or element) the GEODIST
command returns null
as documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, perhaps, ReactiveGeoOperations
needs further refinements down the road, particularly with guards around possible null
values.
@@ -285,7 +288,8 @@ public Mono<V> rightPopAndLeftPush(K sourceKey, K destinationKey, Duration timeo | |||
Assert.isTrue(isZeroOrGreater1Second(timeout), "Duration must be either zero or greater or equal to 1 second"); | |||
|
|||
return createMono( | |||
connection -> connection.bRPopLPush(rawKey(sourceKey), rawKey(destinationKey), timeout).map(this::readValue)); | |||
connection -> connection.bRPopLPush(rawKey(sourceKey), rawKey(destinationKey), timeout) | |||
.map(this::readRequiredValue)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This previous variant was .map(this::readValue)
, line 288.
I was thinking more along the lines of the rightPop(key, :Duration)
overloaded method above on line 262.
But, perhaps the choice of simply .map(this:readRequiredValue)
vs. .mapNotNull(this:readRequiredValue)
is due to the right pop
followed by left push
compound operation??
import org.springframework.data.redis.connection.stream.PendingMessages; | ||
import org.springframework.data.redis.connection.stream.PendingMessagesSummary; | ||
import org.springframework.data.redis.connection.stream.ReadOffset; | ||
import org.springframework.data.redis.connection.stream.*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should avoid star imports.
See spring-projects#2655 Original pull request: spring-projects#2672
See spring-projects#2655 Original pull request: spring-projects#2672
The changes have been merged to |
Please close pull requests and remove their branches after merge. |
We now use
mapNotNull
to map Redis response values to avoidNullPointerExceptions
caused byRedisElementReader
returningnull
.This effectively turns
RedisElementReader
into a filter function that can suppress elements from being emitted.Closes #2655
If merged, we should bring these changes to all maintained 3.x branches.