Repository navigation
Fix hanging retries for Flux-returning methods with caching - #37403
Conversation
sbrannen
left a comment
There was a problem hiding this comment.
Thanks for the PR.
The Flux.defer() approach looks right to me. I applied the change locally and confirmed that both new tests fail without it and pass with it.
Could you please update this PR's description and the commit message to distinguish the two problems this PR addresses?
- Existing bug (
@Cacheable/@CachePut):processPutRequest()has usedpublish().refCount(2)since 6.1, so any resubscription after an error hangs.@Retryablejust makes it easy to hit. - Unreleased regression (
@CacheEvict):processCacheEvicts()copied the same pattern in 26de340 (gh-37309), so aFlux-returning@CacheEvictmethod combined with@Retryablenow hangs, whereas it did not before that commit.
Please also end the commit message with the following trailers:
See gh-37309
Closes gh-37403
Note that annotations such as @Cacheable should be enclosed in backticks in the commit message, so that they don't mention GitHub users.
Also, this should target 7.0.x rather than main, since 26de340 is already on that branch. We will forward merge it to main on our side.
Cheers
cc2fe6c to
6638d91
Compare
Fix an existing bug in processPutRequest() affecting `@Cacheable` and `@CachePut` since 6.1: resubscription after an error hangs while publish().refCount(2) waits for a second subscriber. Also fix an unreleased regression introduced by 26de340 (spring-projectsgh-37309) for `@CacheEvict`, which copied the same pattern into processCacheEvicts(). Create the shared Flux and cache subscriber for each subscription via Flux.defer(). Add regression tests combining reactive caching with `@Retryable`. See spring-projectsgh-37309 Closes spring-projectsgh-37403 Signed-off-by: Hyunwoo Jung <hyunwoojung@kakao.com>
6638d91 to
9801b81
Compare
|
Thanks for the review! I've addressed your feedback:
Please let me know if you have any further feedback. |
This comment was marked as outdated.
This comment was marked as outdated.
sbrannen
left a comment
There was a problem hiding this comment.
Thanks for making the requested changes.
I'll make a final review locally before merging this into 7.0.x and main.
|
Fixed via 440139f |
- Add tests for @CachePut, @Cacheable, and @CacheEvict with Flux resubscription in ReactiveCachingTests, using plain Reactor retry() instead of @Retryable. - Reduce the block() timeouts in ReactiveRetryInterceptorTests from 5 seconds to 1 second so that regressions fail faster. See gh-37403
|
This has been merged into Thanks |
Overview
Combining
@Retryablewith@Cacheableor@CacheEvicton a method returning aFluxcan cause the operation to hang when the publisher fails and a retry is attempted:Problem
ReactiveCachingHandlershares the returnedFluxbetween the caller and an internal subscriber that collects emitted values for cache put or eviction operations, usingpublish().refCount(2). Both subscribers terminate when the source signals an error. On resubscription (for example, due to@Retryable), only the caller subscribes again, leavingrefCount(2)waiting for a second subscriber and preventing a new subscription to the source.This PR addresses two distinct problems caused by this pattern:
@Cacheable/@CachePut):processPutRequest()has usedpublish().refCount(2)since 6.1, so any resubscription after an error hangs.@Retryablejust makes it easy to hit.@CacheEvict):processCacheEvicts()copied the same pattern in 26de340 (@CacheEvicttruncatesFluxresults to the first element #37309), so aFlux-returning@CacheEvictmethod combined with@Retryablenow hangs, whereas it did not before that commit.Fix
Wrap the shared Flux creation and internal subscriber registration in
Flux.defer()so that each subscription, including a retry, creates a new shared Flux and registers a new cache subscriber. Apply this change to both cache put and eviction handling.Tests
Add regression tests for
@Retryablecombined with@Cacheableor@CacheEvict. The tests verify that an initial failure is followed by a successful second subscription, that all expected values are returned, and that the successful operation populates or evicts the cache as appropriate.Related Issues
@CacheEvicttruncatesFluxresults to the first element #37309