We now differentiate exception handling regarding the recovery state. Initial listen fails if the connection is unavailable. Upon recovery after a preceeding subscription we now log the success to create a counterpart to our error logging.
Closes: #2782
Original Pull Request: #2808
Given addListener(:MessageListener, :Collection<Topic>) could be called concurrently from the addMessageListener(:MessageListener, Collection<Topic>) method by multiple Threads, and the RedisMessageListenerContainer Javadoc specifically states that it is safe to call the addMessageListener(..) method conurrently without any external synchronization, and the registeration (or mapping) of listener to Topics is a componund action, then a race condition is possible.
Closes#2755
We now consistently align with the core Spring Framework's use of 'ex' as the variable name for Exceptions handled in catch blocks, and 'ignore' for all Exceptions thrown, but ignored by framework code. Both 'ex' and 'ignore' were appropriately used based on the context and nautre of the Exception handler in the catch block.
Additionally, we use the 'expected' variable name for Exception thrown in tests where the thrown Exception is the expected outcome of the test case.
Only 1 exception exists to these name conventions, and that is 'nested', which was necessarily used in ScanCursor due to the nested try-catch blocks.
Applied consistent use of String.format(..) to Exception messages requiring formatting.
Formatted catch block according to source code formatting style.
Closes#2748
Original pull request: #2749
Additionally:
* Annotates getMaster() with @Nullable.
* Fixes assertion messages for accuracy and consistency.
* Introduces white spacing for readability.
Closes#2747
Judiciously applies minor source code refinements, such as introducing named (local) variable object references to make it clearer the arguments that are being passed to caching method parameters, in favor of self-describing code with intent.
Closes#2742
Replace blocking lock wait with non-blocking flow. Add support for asynchronous storage to persist the cache value after retrieval from the value supplier. Introduce AsyncCacheWriter abstraction to improve functional guards.
Reformat code. Remove redundant tests. Revisit deprecation notices with consistent mention of the version in which the deprecation was introduced.
Refine exception messages when RedisCache does not support async retrieval.
See #2650
Original pull request: #2717
Refactors extractBytes(:ByteBuffer) to call getBytes(:ByteBuffer), thereby avoid the NullPointerException by throwing the more appropriate IllegalArgumentException with a descriptive message instead.
See #2733
We now correctly apply if exists/if not exists constraints on the reactive zadd command.
Previously, we only considered upsert which wasn't sufficient to apply xx/nx.
Closes#2731
Simplify tests. Reuse existing interfaces from Spring. Remove inappropriate nullability annotations and introduce annotations where required.
Replace Future mocking with easier to maintain and to read future method overrides. Remove superfluous code and replace with infrastructure classes provided by Spring Framework.
Consistently name callbacks. Make exception collector concept explicit. Reformat code.
See #2518
Original pull request: #2719
Replace Thread.sleep(..) with Future.get(timeout, :TimeUnit) for 10 microseconds. As a result, Future.isDone() and Future.isCancelled() are no longer necessary. Simply try to get the results within 10 us, and if a TimeoutException is thrown, then set done to false.
10 microseconds is 1/1000 of 10 milliseconds. This means a Redis cluster with 1000 nodes will run in a similar time to Thread.sleep(10L) if all Futures are blocked waiting for the computation to complete and take an equal amount of time to compute the result, which is rarely the case in practice, given different hardware configurations, data access patterns, load balancing/request routing, and so on. However, using Future.get(timeout, :TimeUnit) is more fair than Future.get(), which blocks until a result is returned or an ExecutionException is thrown, thereby starving computationally faster nodes vs. other nodes in the cluster that might be overloaded. In the meantime, some nodes may even complete in the short amount of time when waiting on a single node to complete.
10 microseconds was partially arbitrary, but no more so than Thread.sleep(10L) (10 milliseconds). The main objective was to give each node a chance to complete the computation in a moments notice balanced with the need to quickly check if the computation is done, hence Future.get(timeout, TimeUnit.MICROSECONDS) for sub-millisecond response times. This may need to be further tuned over time, but should serve as a reasonable baseline for the time being. Additionally, this was based on https://redis.io/docs/reference/cluster-spec/#overview-of-redis-cluster-main-components in the Redis documentation, recommending a cluster size of no more than 1000 nodes.
Add test coverage for ClusterCommandExecutor collectResults(..) method.
Cleanup compiler warnings in ClusterCommandExecutorUnitTests.
Closes#2518
Original pull request: #2719
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.
Apply consistent wording to operations documentation.
Adapt to API changes in the Jedis 5.0 driver.
Fix bzPopMaxShouldWorkCorrectly() and bzPopMinShouldWorkCorrectly() tests in JedisClusterConnectionTests.
Jedis 5.0 changed the bzpopmax and bzpopmin Redis commands to no longer return an empty (Array)List internally when evaluating and popping from an empty sorted set. A NullPointerException will be thrown if either bzpopmax or bzpopmin commands are executd on an empty Redis sorted set in Jedis 5.0 (vs. Jedis 4.x):
Closes#2612
Original pull request: #2716
Move executor from ClusterConfiguration to connection factories as the executor is a Spring concept that isn't tied to endpoint details or the client config.
Reorder static factory methods after constructors and property accessors after static factory methods. Inline single-line single-use methods that aren't intended as extension hooks for easier readability.
Disable TaskExecutor disposal on ClusterCommandExecutor.destroy().
Remove NonNull annotations as default non-nullability is defined on the package level.
Simplify tests to use integration tests to avoid excessive mocking.
See #2594
Original pull request: #2669
This change allows users to leverage the VirtualThread facilities and AsyncTaskExecutor implementations provided in and by the core Spring Framework as part of our Loom support theme.
Closes#2594
Original pull request: #2669
Replace qualified class name access of inner classes with simple names and imports.
Remove Java 8 guards. Extend supported temporal types in Jsr310Converters. Remove superfluous converter annotations.
Simplify tests.
See #2677
Original pull request: #2681
We now appropriately handle OffsetDateTime and OffsetTime the same as all other java.time types, supported as simple types on Spring application (persistent) entity classes.
Closes#2677