diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index b3538290ee..e1bb6dcefa 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -33,6 +33,8 @@ Set up test environments with ```make start```, tear down those environments wit
* You can import code style file (located to hbase-formatter.xml) to Eclipse, IntelliJ
* line break by column count seems not working with IntelliJ
* You can run ```make format``` anytime to reformat without IDEs
+* DO NOT format the source codes within `io.redis.examples` test package.
+* A test class name MUST NOT end with `Example`.
## Adding commands
diff --git a/.github/release-drafter-config.yml b/.github/release-drafter-config.yml
index edc2911f43..4607da071c 100644
--- a/.github/release-drafter-config.yml
+++ b/.github/release-drafter-config.yml
@@ -1,5 +1,7 @@
name-template: '$NEXT_MINOR_VERSION'
tag-template: 'v$NEXT_MINOR_VERSION'
+filter-by-commitish: true
+commitish: master
autolabeler:
- label: 'maintenance'
files:
@@ -35,6 +37,8 @@ categories:
labels:
- 'maintenance'
- 'dependencies'
+ - 'documentation'
+ - 'docs'
- 'testing'
change-template: '- $TITLE (#$NUMBER)'
exclude-labels:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index fd7c46dc80..3f472ee7cc 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -24,24 +24,20 @@ jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
-
- strategy:
- fail-fast: false
- matrix:
- language: [ 'java' ]
- # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
- # Learn more:
- # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+ permissions:
+ security-events: write
+ actions: read
+ contents: read
steps:
- name: Checkout repository
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v1
+ uses: github/codeql-action/init@v2
with:
- languages: ${{ matrix.language }}
+ languages: java
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
@@ -50,7 +46,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v1
+ uses: github/codeql-action/autobuild@v2
# âšī¸ Command-line programs to run using the OS shell.
# đ https://git.io/JvXDl
@@ -64,4 +60,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
+ uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/doctests.yml b/.github/workflows/doctests.yml
new file mode 100644
index 0000000000..daa8858b89
--- /dev/null
+++ b/.github/workflows/doctests.yml
@@ -0,0 +1,37 @@
+name: Documentation Tests
+
+on:
+ push:
+ tags-ignore:
+ - '*'
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ doctests:
+ runs-on: ubuntu-latest
+ services:
+ redis-stack:
+ image: redis/redis-stack-server:latest
+ options: >-
+ --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
+ ports:
+ - 6379:6379
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.m2/repository
+ /var/cache/apt
+ key: jedis-${{hashFiles('**/pom.xml')}}
+ - name: Set up Java
+ uses: actions/setup-java@v2
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ - name: Run doctests
+ run: |
+ mvn -Pdoctests test
diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 5e047a650f..84da5938f6 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -10,13 +10,16 @@ on:
- '**/*.rst'
branches:
- master
- - '[0-9].[0-9]'
+ - '[0-9].x'
+ - '[0-9].[0-9].x'
pull_request:
branches:
- master
- - '[0-9].[0-9]'
+ - '[0-9].x'
+ - '[0-9].[0-9].x'
schedule:
- cron: '0 1 * * *' # nightly build
+ workflow_dispatch:
jobs:
@@ -45,16 +48,33 @@ jobs:
- name: Maven offline
run: |
mvn -q dependency:go-offline
+ - name: Build docs
+ run: |
+ mvn javadoc:jar
- name: Run tests
run: |
TEST="" make test
env:
JVM_OPTS: -Xmx3200m
TERM: dumb
- - name: redismod docker
- run: docker run -p 52567:6379 -d redislabs/redismod:edge
- - name: Run tests
+ - name: sleep 10s
+ run: sleep 10s
+ - name: Make - start
+ run: |
+ make start
+ sleep 2s
+ - name: Docker - mod or stack
+ run: docker run -p 52567:6379 -d redis/redis-stack-server:edge
+ - name: Test commands - default protocol
+ run: mvn -Dtest="redis.clients.jedis.commands.**" test
+ - name: Test commands - RESP3 protocol
+ run: mvn -DjedisProtocol=3 -Dtest="redis.clients.jedis.commands.**" test
+ - name: Test module commands - default protocol
run: mvn -DmodulesDocker="localhost:52567" -Dtest="redis.clients.jedis.modules.**" test
+ - name: Test module commands - RESP3 protocol
+ run: mvn -DjedisProtocol=3 -DmodulesDocker="localhost:52567" -Dtest="redis.clients.jedis.modules.**" test
+ - name: Make - stop
+ run: make stop
- name: Codecov
run: |
bash <(curl -s https://codecov.io/bash)
diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml
index 6c8ad1a962..8a409b8331 100644
--- a/.github/workflows/snapshot.yml
+++ b/.github/workflows/snapshot.yml
@@ -6,7 +6,8 @@ on:
push:
branches:
- master
- - '[0-9].[0-9]'
+ - '[0-9].x'
+ workflow_dispatch:
jobs:
diff --git a/.github/workflows/version-and-release.yml b/.github/workflows/version-and-release.yml
index 007d8875e8..7c996e5bd5 100644
--- a/.github/workflows/version-and-release.yml
+++ b/.github/workflows/version-and-release.yml
@@ -16,7 +16,7 @@ jobs:
run: |
realversion="${GITHUB_REF/refs\/tags\//}"
realversion="${realversion//v/}"
- echo "::set-output name=VERSION::$realversion"
+ echo "VERSION=$realversion" >> $GITHUB_OUTPUT
- name: Set up publishing to maven central
uses: actions/setup-java@v2
@@ -32,14 +32,14 @@ jobs:
- name: Install gpg key
run: |
- cat <(echo -e "${{ secrets.OSSRH_GPG_SECRET_KEY }}") | gpg --batch --import
+ cat <(echo -e "${{ secrets.OSSH_GPG_SECRET_KEY }}") | gpg --batch --import
gpg --list-secret-keys --keyid-format LONG
- name: Publish
run: |
mvn --no-transfer-progress \
--batch-mode \
- -Dgpg.passphrase='${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }}' \
+ -Dgpg.passphrase='${{ secrets.OSSH_GPG_SECRET_KEY_PASSWORD }}' \
-DskipTests deploy -P release
env:
MAVEN_USERNAME: ${{secrets.OSSH_USERNAME}}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000..15c4dd523a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021-2023, Redis, inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/LICENSE.txt b/LICENSE.txt
deleted file mode 100644
index 7b8b1cee63..0000000000
--- a/LICENSE.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-Copyright (c) 2010 Jonathan Leibiusky
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 2987ad80dd..6e63f1b6ce 100644
--- a/Makefile
+++ b/Makefile
@@ -209,7 +209,7 @@ daemonize yes
protected-mode no
requirepass cluster
port 7379
-cluster-node-timeout 50
+cluster-node-timeout 15000
pidfile /tmp/redis_cluster_node1.pid
logfile /tmp/redis_cluster_node1.log
save ""
@@ -223,7 +223,7 @@ daemonize yes
protected-mode no
requirepass cluster
port 7380
-cluster-node-timeout 50
+cluster-node-timeout 15000
pidfile /tmp/redis_cluster_node2.pid
logfile /tmp/redis_cluster_node2.log
save ""
@@ -237,7 +237,7 @@ daemonize yes
protected-mode no
requirepass cluster
port 7381
-cluster-node-timeout 50
+cluster-node-timeout 15000
pidfile /tmp/redis_cluster_node3.pid
logfile /tmp/redis_cluster_node3.log
save ""
@@ -251,7 +251,7 @@ daemonize yes
protected-mode no
requirepass cluster
port 7382
-cluster-node-timeout 50
+cluster-node-timeout 15000
pidfile /tmp/redis_cluster_node4.pid
logfile /tmp/redis_cluster_node4.log
save ""
@@ -265,7 +265,7 @@ daemonize yes
protected-mode no
requirepass cluster
port 7383
-cluster-node-timeout 5000
+cluster-node-timeout 15000
pidfile /tmp/redis_cluster_node5.pid
logfile /tmp/redis_cluster_node5.log
save ""
diff --git a/README.md b/README.md
index 3620931c2b..4c7c507d21 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.txt)
[![Integration](https://github.com/redis/jedis/actions/workflows/integration.yml/badge.svg?branch=master)](https://github.com/redis/jedis/actions/workflows/integration.yml)
[![codecov](https://codecov.io/gh/redis/jedis/branch/master/graph/badge.svg?token=pAstxAAjYo)](https://codecov.io/gh/redis/jedis)
-[![Discord](https://img.shields.io/discord/697882427875393627?style=flat-square)](https://discord.gg/qRhBuY8Z)
+[![Discord](https://img.shields.io/discord/697882427875393627?style=flat-square)](https://discord.gg/redis)
## What is Jedis?
@@ -14,14 +14,37 @@ Jedis is a Java client for [Redis](https://github.com/redis/redis "Redis") desig
Are you looking for a high-level library to handle object mapping? See [redis-om-spring](https://github.com/redis/redis-om-spring)!
-## Contributing
+## How do I Redis?
-We'd love your contributions!
+[Learn for free at Redis University](https://university.redis.com/)
-**Bug reports** are always welcome! [You can open a bug report on GitHub](https://github.com/redis/jedis/issues/new).
+[Build faster with the Redis Launchpad](https://launchpad.redis.com/)
-You can also **contribute documentation** -- or anything to improve Jedis. Please see
-[contribution guideline](https://github.com/redis/jedis/blob/master/.github/CONTRIBUTING.md) for more details.
+[Try the Redis Cloud](https://redis.com/try-free/)
+
+[Dive in developer tutorials](https://developer.redis.com/)
+
+[Join the Redis community](https://redis.com/community/)
+
+[Work at Redis](https://redis.com/company/careers/jobs/)
+
+## Supported Redis versions
+
+The most recent version of this library supports redis version
+[5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES),
+[6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES),
+[6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES),
+[7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES) and
+[7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES).
+
+The table below highlights version compatibility of the most-recent library versions and Redis versions. Compatibility means communication features, and Redis command capabilities.
+
+
+| Jedis version | Supported Redis versions | JDK Compatibility |
+|---------------|--------------------------------|-------------------|
+| 3.9+ | 5.0 and 6.2 Family of releases | 8, 11 |
+| >= 4.0 | Version 5.0 to current | 8, 11, 17 |
+| >= 5.0 | Version 6.0 to current | 8, 11, 17 |
## Getting started
@@ -31,7 +54,7 @@ To get started with Jedis, first add it as a dependency in your Java project. If
redis.clientsjedis
- 4.3.0
+ 5.0.0
```
@@ -67,7 +90,7 @@ for the complete list of supported commands.
### Easier way of using connection pool
-Using a *try-with-resources* block for each command may be cumbursome, so you may consider using JedisPooled.
+Using a *try-with-resources* block for each command may be cumbersome, so you may consider using JedisPooled.
```java
JedisPooled jedis = new JedisPooled("localhost", 6379);
@@ -104,24 +127,44 @@ Jedis includes support for [Redis modules](https://redis.io/docs/modules/) such
See the [RedisJSON Jedis](docs/redisjson.md) or [RediSearch Jedis](docs/redisearch.md) for details.
+## Failover
+
+Jedis supports retry and failover for your Redis deployments. This is useful when:
+
+1. You have more than one Redis deployment. This might include two independent Redis servers or two or more Redis databases replicated across multiple [active-active Redis Enterprise](https://docs.redis.com/latest/rs/databases/active-active/) clusters.
+2. You want your application to connect to one deployment at a time and to fail over to the next available deployment if the first deployment becomes unavailable.
+
+For the complete failover configuration options and examples, see the [Jedis failover docs](docs/failover.md).
+
## Documentation
The [Jedis wiki](http://github.com/redis/jedis/wiki) contains several useful articles for using Jedis.
You can also check the [latest Jedis Javadocs](https://www.javadoc.io/doc/redis.clients/jedis/latest/index.html).
+Some specific use-case examples can be found in [`redis.clients.jedis.examples`
+package](src/test/java/redis/clients/jedis/examples/) of the test source codes.
+
## Troubleshooting
If you run into trouble or have any questions, we're here to help!
-Hit us up on the [Redis Discord Server](http://discord.gg/redis) or [open an issue on GitHub](https://github.com/redis/jedis).
+Hit us up on the [Redis Discord Server](http://discord.gg/redis) or
+[Jedis GitHub Discussions](https://github.com/redis/jedis/discussions) or
+[Jedis mailing list](http://groups.google.com/group/jedis_redis).
-You can also find help on the [Jedis mailing list](http://groups.google.com/group/jedis_redis) or the
-[GitHub Discussions](https://github.com/redis/jedis/discussions).
+## Contributing
+
+We'd love your contributions!
+
+Bug reports are always welcome! [You can open a bug report on GitHub](https://github.com/redis/jedis/issues/new).
+
+You can also contribute documentation -- or anything to improve Jedis. Please see
+[contribution guideline](https://github.com/redis/jedis/blob/master/.github/CONTRIBUTING.md) for more details.
## License
-Jedis is licensed under the [MIT license](https://github.com/redis/jedis/blob/master/LICENSE.txt).
+Jedis is licensed under the [MIT license](https://github.com/redis/jedis/blob/master/LICENSE).
## Sponsorship
diff --git a/docs/3to4-primitives.md b/docs/3to4-primitives.md
index ebda28ee25..76049f34ea 100644
--- a/docs/3to4-primitives.md
+++ b/docs/3to4-primitives.md
@@ -1,5 +1,5 @@
-## The following methods now return primitive values (`long`/`boolean`/`double`
-instead of `Long`/`Boolean`/`Double`):
+## The following methods now return primitive values:
+\>> `long`/`boolean`/`double` instead of `Long`/`Boolean`/`Double`:
- dbSize()
- lastsave()
diff --git a/docs/3to4.md b/docs/3to4.md
index 58a8247531..af1df0158e 100644
--- a/docs/3to4.md
+++ b/docs/3to4.md
@@ -1,4 +1,4 @@
-# Jedis 3 to Jedis 4 Breaking Changes
+# Jedis 4 Breaking Changes
- The `BinaryJedis` and `BinaryJedisCluster` classes have been removed.
diff --git a/docs/breaking-5.md b/docs/breaking-5.md
new file mode 100644
index 0000000000..4a013c3800
--- /dev/null
+++ b/docs/breaking-5.md
@@ -0,0 +1,161 @@
+# Jedis 5 Breaking Changes
+
+- All variants of `blmpop` and `bzmpop` methods now take `double timeout` parameter instead of `long timeout` parameter.
+ This is breaking ONLY IF you are using `Long` for timeout.
+
+- `Reducer` abstract class is refactored:
+ - **`Reducer(String field)` constructor is removed; `Reducer(String name, String field)` constructor is added.**
+ - **`Reducer(String name)` constructor is added; it will cause runtime error with older `Reducer(String field)` constructor.**
+ - `getName` method is removed.
+ - `getAlias` method is removed.
+ - `setAlias` method is removed; use `as` method.
+ - `setAliasAsField` method is removed.
+ - `getOwnArgs` method is now abstract.
+ - `getArgs` method is removed.
+
+- `quit()` method has been removed from `Connection` and `ServerCommands` interface and implementations.
+
+- `updatePassword(String password)` method has been removed from `JedisClientConfig` and implementations.
+
+- `setPassword(String password)` method has been removed from both `JedisFactory` and `ConnectionFactory` classes.
+
+- Both `bzpopmax(double timeout, String... keys)` and `bzpopmin(double timeout, String... keys)` now return `KeyValue` (instead of `KeyedZSetElement`).
+
+- Both `bzpopmax(double timeout, byte[]... keys)` and `bzpopmin(double timeout, byte[]... keys)` now return `KeyValue` (instead of `List`).
+
+- Following methods now return `KeyValue` instead of `KeyedListElement`:
+ - `blpop(double timeout, String key)`
+ - `blpop(double timeout, String... keys)`
+ - `brpop(double timeout, String key)`
+ - `brpop(double timeout, String... keys)`
+
+- Following methods now return `KeyValue` instead of `List`:
+ - `blpop(double timeout, byte[]... keys)`
+ - `brpop(double timeout, byte[]... keys)`
+
+- `zdiff(String... keys)` method now returns `List` (instead of `Set`).
+- `zdiff(byte[]... keys)` method now returns `List` (instead of `Set`).
+- Both `zdiffWithScores(String... keys)` and `zdiffWithScores(byte[]... keys)` methods now return `List` (instead of `Set`).
+
+- `zinter(ZParams params, String... keys)` method now returns `List` (instead of `Set`).
+- `zinter(ZParams params, byte[]... keys)` method now returns `List` (instead of `Set`).
+- Both `zinterWithScores(ZParams params, String... keys)` and `zinterWithScores(ZParams params, byte[]... keys)` methods now return `List` (instead of `Set`).
+
+- `zunion(ZParams params, String... keys)` method now returns `List` (instead of `Set`).
+- `zunion(ZParams params, byte[]... keys)` method now returns `List` (instead of `Set`).
+- Both `zunionWithScores(ZParams params, String... keys)` and `zunionWithScores(ZParams params, byte[]... keys)` methods now return `List` (instead of `Set`).
+
+- Both `configGet(String pattern)` and `configGet(String... patterns)` methods now return `Map` instead of `List`.
+- Both `configGet(byte[] pattern)` and `configGet(byte[]... patterns)` methods now return `Map` instead of `List`.
+
+- New `aclDelUser(String... names)` method replaces `aclDelUser(String name)` and `aclDelUser(String name, String... names)` methods.
+- New `aclDelUser(byte[]... names)` method replaces `aclDelUser(byte[] name)` and `aclDelUser(byte[] name, byte[]... names)` methods.
+
+- `tsMGet(TSMGetParams multiGetParams, String... filters)` method now returns `Map` instead of `List>`.
+
+- Following methods now return `Map` instead of `List`:
+ - `tsMRange(long fromTimestamp, long toTimestamp, String... filters)`
+ - `tsMRange(TSMRangeParams multiRangeParams)`
+ - `tsMRevRange(long fromTimestamp, long toTimestamp, String... filters)`
+ - `tsMRevRange(TSMRangeParams multiRangeParams)`
+
+- `jsonNumIncrBy(String key, Path2 path, double value)` method now returns `Object` instead of `JSONArray`.
+ - The returning object would still be JSONArray for all previous cases. So simple type casting is enough to handle this change.
+ - The returning object will be `List` when running under RESP3 protocol.
+
+- `getAgeSeconds()` in `AccessControlLogEntry` now returns `Double` instead of `String`.
+
+- Both `ftConfigGet(String option)` and `ftConfigGet(String indexName, String option)` methods now return `Map` instead of `Map`.
+
+- `ftList()` method now returns `Set` instead of `List`.
+
+- `graphSlowlog(String graphName)` now returns `List>` (instead of `List>`).
+
+- `CommandListFilterByParams` now throws `IllegalArgumentException` (instead of `JedisDataException`) in case of unfulfilling filter.
+
+- `FailoverParams` now throws `IllegalArgumentException` (instead of `IllegalStateException`) in case of unfulfilling optional arguments.
+
+- `XPendingParams` now throws `IllegalArgumentException` (instead of `IllegalStateException`) in case of unfulfilling optional arguments.
+
+- `get()` option has been removed from `SetParams`. Following methods have been added in Jedis/UnifiedJedis for convenience:
+ - `setGet(String key, String value)` method has been added in `StringCommands` interface.
+ - `setGet(byte[] key, byte[] value)` method has been added in `StringBinaryCommands` interface.
+
+- `xpending(String key, String groupName, StreamEntryID start, StreamEntryID end, int count, String consumerName)` method has been removed from everywhere.
+ - Use `xpending(java.lang.String, java.lang.String, redis.clients.jedis.params.XPendingParams)` instead.
+
+- `xpending(byte[] key, byte[] groupName, byte[] start, byte[] end, int count, byte[] consumerName)` method has been removed from everywhere.
+ - Use `xpending(byte[], byte[], redis.clients.jedis.params.XPendingParams)` instead.
+
+- `retentionTime(long retentionTime)` method in `TSAlterParams` has been removed. Use `retention(long)` method instead.
+
+- Following classes have been removed:
+ - `KeyedZSetElement`
+ - `KeyedListElement`
+ - `TSKeyValue`
+ - `TSKeyedElements`
+ - `Limit`
+
+- Following BuilderFactory implementations have been removed:
+ - `BYTE_ARRAY` (use `BINARY`)
+ - `BYTE_ARRAY_LIST` (use `BINARY_LIST`)
+ - `BINARY_MAP_FROM_PAIRS`
+ - `STRING_ORDERED_SET`
+
+- All _payload_ related parameters are removed from _search_ related classes; namely `Document`, `IndexDefinition`, `Query`.
+
+- `topkCount(String key, String... items)` method has been removed from everywhere.
+
+- Following methods supporting JSON.RESP command have been removed:
+ - `jsonResp(String key)`
+ - `jsonResp(String key, Path path)`
+ - `jsonResp(String key, Path2 path)`
+
+- `RedisJsonCommands` and `RedisJsonPipelineCommands` interfaces have been moved into `redis.clients.jedis.json.commands` package.
+
+- `AbortedTransactionException` is removed.
+
+- `Queable` class is removed.
+
+- `Params` abstract class is removed.
+ - `toString()` support used by its sub-classes is now unavailable.
+
+- `getParams()` method is removed from `SortingParams` class.
+
+- Both `SEARCH_AGGREGATION_RESULT` and `SEARCH_AGGREGATION_RESULT_WITH_CURSOR` implementations from `SearchBuilderFactory` class have been moved to `AggregationResult` class.
+
+- All `AggregationResult` constructors have been made `private`.
+
+- `getArgs()`, `getArgsString()` and `serializeRedisArgs(List redisArgs)` methods have been removed from `AggregationBuilder`.
+
+- `totalResults` variable in `AggregationResult` has been made private. Use `getTotalResults()` method instead.
+
+- `getArgs()` and `limit(Limit limit)` methods have been removed from `Group` class.
+
+- `addCommandEncodedArguments` and `addCommandBinaryArguments` methods have been removed from `FieldName` class.
+
+- `addObjects(int[] ints)` method has been removed from `CommandArguments`.
+
+- Following methods have been removed:
+ - `strAlgoLCSStrings(String strA, String strB, StrAlgoLCSParams params)`
+ - `strAlgoLCSStrings(byte[] strA, byte[] strB, StrAlgoLCSParams params)`
+ - `strAlgoLCSKeys(String keyA, String keyB, StrAlgoLCSParams params)`
+ - `strAlgoLCSKeys(byte[] keyA, byte[] keyB, StrAlgoLCSParams params)`
+
+- `StrAlgoLCSParams` class has been removed.
+
+- Following methods have been removed from all Pipeline classes:
+ - `ftCursorRead(String indexName, long cursorId, int count)`
+ - `ftCursorDel(String indexName, long cursorId)`
+ - `ftDropIndex(String indexName)`
+ - `ftDropIndexDD(String indexName)`
+ - `ftAliasAdd(String aliasName, String indexName)`
+ - `ftAliasUpdate(String aliasName, String indexName)`
+ - `ftAliasDel(String aliasName)`
+
+- `JedisSentineled(String masterName, Set sentinels, JedisClientConfig masterClientConfig, JedisClientConfig sentinelClientConfig)` and
+`JedisSentineled(String masterName, Set sentinels, GenericObjectPoolConfig poolConfig, JedisClientConfig masterClientConfig, JedisClientConfig sentinelClientConfig)`
+constructors have been removed.
+
+- `JedisClusterInfoCache(JedisClientConfig clientConfig)` and `JedisClusterInfoCache(JedisClientConfig clientConfig, GenericObjectPoolConfig poolConfig)`
+constructors have been removed.
diff --git a/docs/failover.md b/docs/failover.md
new file mode 100644
index 0000000000..8414e41376
--- /dev/null
+++ b/docs/failover.md
@@ -0,0 +1,225 @@
+# Failover with Jedis
+
+Jedis supports failover for your Redis deployments. This is useful when:
+1. You have more than one Redis deployment. This might include two independent Redis servers or two or more Redis databases replicated across multiple [active-active Redis Enterprise](https://docs.redis.com/latest/rs/databases/active-active/) clusters.
+2. You want your application to connect to and use one deployment at a time.
+3. You want your application to fail over to the next available deployment if the current deployment becomes unavailable.
+
+Jedis will fail over to a subsequent Redis deployment after reaching a configurable failure threshold.
+This failure threshold is implemented using a [circuit breaker pattern](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern).
+
+You can also configure Jedis to retry failed calls to Redis.
+Once a maximum number of retries have been exhausted, the circuit breaker will record a failure.
+When the circuit breaker reaches its failure threshold, a failover will be triggered on the subsequent operation.
+
+The remainder of this guide describes:
+
+* A basic failover configuration
+* Supported retry and circuit breaker settings
+* Failback and the cluster selection API
+
+We recommend that you read this guide carefully and understand the configuration settings before enabling Jedis failover
+in production.
+
+## Basic usage
+
+To configure Jedis for failover, you specify an ordered list of Redis databases.
+By default, Jedis will connect to the first Redis database in the list. If the first database becomes unavailable,
+Jedis will attempt to connect to the next database in the list, and so on.
+
+Suppose you run two Redis deployments.
+We'll call them `redis-east` and `redis-west`.
+You want your application to first connect to `redis-east`.
+If `redis-east` becomes unavailable, you want your application to connect to `redis-west`.
+
+Let's look at one way of configuring Jedis for this scenario.
+
+First, create an array of `ClusterConfig` objects, one for each Redis database.
+
+```java
+JedisClientConfig config = DefaultJedisClientConfig.builder().user("cache").password("secret").build();
+
+ClusterConfig[] clientConfigs = new ClusterConfig[2];
+clientConfigs[0] = new ClusterConfig(new HostAndPort("redis-east.example.com", 14000), config);
+clientConfigs[1] = new ClusterConfig(new HostAndPort("redis-west.example.com", 14000), config);
+```
+
+The configuration above represents your two Redis deployments: `redis-east` and `redis-west`.
+You'll use this array of configuration objects to create a connection provider that supports failover.
+
+Use the `MultiClusterClientConfig` builder to set your preferred retry and failover configuration, passing in the client configs you just created.
+Then build a `MultiClusterPooledConnectionProvider`.
+
+```java
+MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder(clientConfigs);
+builder.circuitBreakerSlidingWindowSize(10);
+builder.circuitBreakerSlidingWindowMinCalls(1);
+builder.circuitBreakerFailureRateThreshold(50.0f);
+
+MultiClusterPooledConnectionProvider provider = new MultiClusterPooledConnectionProvider(builder.build());
+```
+
+Internally, the connection provider uses a [highly configurable circuit breaker and retry implementation](https://resilience4j.readme.io/docs/circuitbreaker) to determine when to fail over.
+In the configuration here, we've set a sliding window size of 10 and a failure rate threshold of 50%.
+This means that a failover will be triggered if 5 out of any 10 calls to Redis fail.
+
+Once you've configured and created a `MultiClusterPooledConnectionProvider`, instantiate a `UnifiedJedis` instance for your application, passing in the provider you just created:
+
+```java
+UnifiedJedis jedis = new UnifiedJedis(provider);
+```
+
+You can now use this `UnifiedJedis` instance, and the connection management and failover will be handled transparently.
+
+## Configuration options
+
+Under the hood, Jedis' failover support relies on [resilience4j](https://resilience4j.readme.io/docs/getting-started),
+a fault-tolerance library that implements [retry](https://resilience4j.readme.io/docs/retry) and [circuit breakers](https://resilience4j.readme.io/docs/circuitbreaker).
+
+Once you configure Jedis for failover using the `MultiClusterPooledConnectionProvider`, each call to Redis is decorated with a resilience4j retry and circuit breaker.
+
+By default, any call that throws a `JedisConnectionException` will be retried up to 3 times.
+If the call continues to fail after the maximum number of retry attempts, then the circuit breaker will record a failure.
+
+The circuit breaker maintains a record of failures in a sliding window data structure.
+If the failure rate reaches a configured threshold (e.g., when 50% of the last 10 calls have failed),
+then the circuit breaker's state transitions from `CLOSED` to `OPEN`.
+When this occurs, Jedis will attempt to connect to the next Redis database in its client configuration list.
+
+The supported retry and circuit breaker settings, and their default values, are described below.
+You can configure any of these settings using the `MultiClusterClientConfig.Builder` builder.
+Refer the basic usage above for an example of this.
+
+### Retry configuration
+
+Jedis uses the following retry settings:
+
+| Setting | Default value | Description |
+|----------------------------------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Max retry attempts | 3 | Maximum number of retry attempts (including the initial call) |
+| Retry wait duration | 500 ms | Number of milliseconds to wait between retry attempts |
+| Wait duration backoff multiplier | 2 | Exponential backoff factor multiplied against wait duration between retries. For example, with a wait duration of 1 second and a multiplier of 2, the retries would occur after 1s, 2s, 4s, 8s, 16s, and so on. |
+| Retry included exception list | `JedisConnectionException` | A list of `Throwable` classes that count as failures and should be retried. |
+| Retry ignored exception list | Empty list | A list of `Throwable` classes to explicitly ignore for the purposes of retry. |
+
+To disable retry, set `maxRetryAttempts` to 1.
+
+### Circuit breaker configuration
+
+Jedis uses the following circuit breaker settings:
+
+| Setting | Default value | Description |
+|-----------------------------------------|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Sliding window type | `COUNT_BASED` | The type of sliding window used to record the outcome of calls. Options are `COUNT_BASED` and `TIME_BASED`. |
+| Sliding window size | 100 | The size of the sliding window. Units depend on sliding window type. When `COUNT_BASED`, the size represents number of calls. When `TIME_BASED`, the size represents seconds. |
+| Sliding window min calls | 100 | Minimum number of calls required (per sliding window period) before the CircuitBreaker will start calculating the error rate or slow call rate. |
+| Failure rate threshold | `50.0f` | Percentage of calls within the sliding window that must fail before the circuit breaker transitions to the `OPEN` state. |
+| Slow call duration threshold | 60000 ms | Duration threshold above which calls are classified as slow and added to the sliding window. |
+| Slow call rate threshold | `100.0f` | Percentage of calls within the sliding window that exceed the slow call duration threshold before circuit breaker transitions to the `OPEN` state. |
+| Circuit breaker included exception list | `JedisConnectionException` | A list of `Throwable` classes that count as failures and add to the failure rate. |
+| Circuit breaker ignored exception list | Empty list | A list of `Throwable` classes to explicitly ignore for failure rate calculations. | |
+
+### Failover callbacks
+
+In the event that Jedis fails over, you may wish to take some action. This might include logging a warning, recording
+a metric, or externally persisting the cluster connection state, to name just a few examples. For this reason,
+`MultiPooledConnectionProvider` lets you register a custom callback that will be called whenever Jedis
+fails over to a new cluster.
+
+To use this feature, you'll need to design a class that implements `java.util.function.Consumer`.
+This class must implement the `accept` method, as you can see below.
+
+```java
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.function.Consumer;
+
+public class FailoverReporter implements Consumer {
+
+ @Override
+ public void accept(String clusterName) {
+ Logger logger = LoggerFactory.getLogger(FailoverReporter.class);
+ logger.warn("Jedis failover to cluster: " + clusterName);
+ }
+}
+```
+
+You can then pass an instance of this class to your `MultiPooledConnectionProvider`.
+
+```
+FailoverReporter reporter = new FailoverReporter();
+provider.setClusterFailoverPostProcessor(reporter);
+```
+
+The provider will call your `accept` whenever a faoliver occurs.
+
+## Failing back
+
+We believe that failback should not be automatic.
+If Jedis fails over to a new cluster, Jedis will _not_ automatically fail back to the cluster that it was previously connected to.
+This design prevents a scenario in which Jedis fails back to a cluster that may not be entirely healthy yet.
+
+That said, we do provide an API that you can use to implement automated failback when this is appropriate for your application.
+
+## Failback scenario
+
+When a failover is triggered, Jedis will attempt to connect to the next Redis server in the list of server configurations
+you provide at setup.
+
+For example, recall the `redis-east` and `redis-west` deployments from the basic usage example above.
+Jedis will attempt to connect to `redis-east` first.
+If `redis-east` becomes unavailable (and the circuit breaker transitions), then Jedis will attempt to use `redis-west`.
+
+Now suppose that `redis-east` eventually comes back online.
+You will likely want to fail your application back to `redis-east`.
+However, Jedis will not fail back to `redis-east` automatically.
+
+In this case, we recommend that you first ensure that your `redis-east` deployment is healthy before you fail back your application.
+
+## Failback behavior and cluster selection API
+
+Once you've determined that it's safe to fail back to a previously-unavailable cluster,
+you need to decide how to trigger the failback. There are two ways to accomplish this:
+
+1. Use the cluster selection API
+2. Restart your application
+
+### Fail back using the cluster selection API
+
+`MultiClusterPooledConnectionProvider` exposes a method that you can use to manually select which cluster Jedis should use.
+To select a different cluster to use, pass the cluster's numeric index to `setActiveMultiClusterIndex()`.
+
+The cluster's index is a 1-based index derived from its position in the client configuration.
+For example, suppose you configure Jedis with the following client configs:
+
+```
+ClusterConfig[] clientConfigs = new ClusterConfig[2];
+clientConfigs[0] = new ClusterConfig(new HostAndPort("redis-east.example.com", 14000), config);
+clientConfigs[1] = new ClusterConfig(new HostAndPort("redis-west.example.com", 14000), config);
+```
+
+In this case, `redis-east` will have an index of `1`, and `redis-west` will have an index of `2`.
+To select and fail back to `redis-east`, you would call the function like so:
+
+```
+provider.setActiveMultiClusterIndex(1);
+```
+
+This method is thread-safe.
+
+If you decide to implement manual failback, you will need a way for external systems to trigger this method in your
+application. For example, if your application exposes a REST API, you might consider creating a REST endpoint
+to call `setActiveMultiClusterIndex` and fail back the application.
+
+### Fail back by restarting the application
+
+When your application starts, Jedis will attempt to connect to each cluster in the order that the clusters appear
+in your client configuration. It's important to understand this, especially in the case where Jedis has failed over.
+If Jedis has failed over to a new cluster, then restarting the application may result in an inadvertent failback.
+This can happen only if a failed cluster comes back online and the application subsequently restarts.
+
+If you need to avoid this scenario, consider using a failover callback, as described above, to externally record
+the name of the cluster that your application was most recently connected to. You can then check this state on startup
+to ensure that you application only connects to the most recently used cluster. For assistance with this technique,
+[start a discussion](https://github.com/redis/jedis/discussions/new?category=q-a).
diff --git a/docs/jedis-maven.md b/docs/jedis-maven.md
index 1c5b0f2598..6466b1ef3a 100644
--- a/docs/jedis-maven.md
+++ b/docs/jedis-maven.md
@@ -6,7 +6,7 @@
redis.clientsjedis
- 4.3.0
+ 5.0.0
```
@@ -28,7 +28,7 @@ and
redis.clientsjedis
- 4.4.0-SNAPSHOT
+ 5.1.0-SNAPSHOT
```
diff --git a/pom.xml b/pom.xml
index 836a5ae662..e2d0183a05 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
jarredis.clientsjedis
- 4.4.0-SNAPSHOT
+ 5.2.0-SNAPSHOTJedisJedis is a blazingly small and sane Redis java client.https://github.com/redis/jedis
@@ -19,7 +19,7 @@
Jedis Mailing Listjedis_redis@googlegroups.com
- http://groups.google.com/group/jedis_redis
+ https://groups.google.com/group/jedis_redis
@@ -27,14 +27,14 @@
MIT
- http://github.com/redis/jedis/raw/master/LICENSE.txt
+ https://github.com/redis/jedis/blob/master/LICENSErepogithub
- http://github.com/redis/jedis/issues
+ https://github.com/redis/jedis/issues
@@ -46,8 +46,11 @@
github
- 1.7.36redis.clients.jedis
+ 1.7.36
+ 1.7.1
+ 2.16.0
+ 3.2.3
@@ -59,12 +62,12 @@
org.apache.commonscommons-pool2
- 2.11.1
+ 2.12.0org.jsonjson
- 20220924
+ 20231013com.google.code.gson
@@ -72,6 +75,22 @@
2.10.1
+
+
+ com.kohlschutter.junixsocket
+ junixsocket-core
+ 2.8.3
+ pom
+ test
+
+
+
+ org.locationtech.jts
+ jts-core
+ 1.19.0
+ test
+
+
junitjunit
@@ -80,8 +99,8 @@
org.hamcrest
- hamcrest-library
- 1.3
+ hamcrest
+ 2.2test
@@ -91,18 +110,43 @@
test
- com.kohlschutter.junixsocket
- junixsocket-core
- 2.6.1
- pom
+ org.mockito
+ mockito-inline
+ 4.11.0test
- org.mockito
- mockito-inline
- 3.12.4
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}test
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ ${jackson.version}
+ test
+
+
+
+
+ io.github.resilience4j
+ resilience4j-all
+ ${resilience4j.version}
+ true
+
+
+ io.github.resilience4j
+ resilience4j-circuitbreaker
+ ${resilience4j.version}
+ true
+
+
+ io.github.resilience4j
+ resilience4j-retry
+ ${resilience4j.version}
+ true
+
@@ -117,11 +161,17 @@
+
+
+ src/main/resources
+ true
+
+ org.jacocojacoco-maven-plugin
- 0.8.5
+ 0.8.11
@@ -139,7 +189,7 @@
maven-compiler-plugin
- 3.10.1
+ 3.11.01.8
@@ -147,17 +197,20 @@
maven-surefire-plugin
- 2.22.2
+ ${maven.surefire.version}${redis-hosts}
+
+ **/examples/*Example.java
+ maven-source-plugin
- 3.2.1
+ 3.3.0true
@@ -172,7 +225,7 @@
maven-javadoc-plugin
- 3.4.1
+ 3.6.3false
@@ -190,7 +243,7 @@
maven-release-plugin
- 2.5.3
+ 3.0.1org.sonatype.plugins
@@ -226,7 +279,7 @@
org.apache.felixmaven-bundle-plugin
- 5.1.8
+ 5.1.9bundle-manifest
@@ -247,7 +300,7 @@
maven-gpg-plugin
- 3.0.1
+ 3.1.0--pinentry-mode
@@ -267,5 +320,19 @@
+
+ doctests
+
+
+
+ maven-surefire-plugin
+ ${maven.surefire.version}
+
+ **/examples/*Example.java
+
+
+
+
+
diff --git a/src/main/java/redis/clients/jedis/AbstractPipeline.java b/src/main/java/redis/clients/jedis/AbstractPipeline.java
new file mode 100644
index 0000000000..f4eb0335dc
--- /dev/null
+++ b/src/main/java/redis/clients/jedis/AbstractPipeline.java
@@ -0,0 +1,26 @@
+package redis.clients.jedis;
+
+import java.io.Closeable;
+
+public abstract class AbstractPipeline extends PipeliningBase implements Closeable {
+
+ protected AbstractPipeline(CommandObjects commandObjects) {
+ super(commandObjects);
+ }
+
+ @Override
+ public abstract void close();
+
+ /**
+ * Synchronize pipeline by reading all responses.
+ */
+ public abstract void sync();
+
+ public Response publish(String channel, String message) {
+ return appendCommand(commandObjects.publish(channel, message));
+ }
+
+ public Response publish(byte[] channel, byte[] message) {
+ return appendCommand(commandObjects.publish(channel, message));
+ }
+}
diff --git a/src/main/java/redis/clients/jedis/AbstractTransaction.java b/src/main/java/redis/clients/jedis/AbstractTransaction.java
new file mode 100644
index 0000000000..ed6f397caa
--- /dev/null
+++ b/src/main/java/redis/clients/jedis/AbstractTransaction.java
@@ -0,0 +1,35 @@
+package redis.clients.jedis;
+
+import java.io.Closeable;
+import java.util.List;
+
+public abstract class AbstractTransaction extends PipeliningBase implements Closeable {
+
+ protected AbstractTransaction() {
+ super(new CommandObjects());
+ }
+
+ public abstract void multi();
+
+ /**
+ * Must be called before {@link AbstractTransaction#multi() MULTI}.
+ */
+ public abstract String watch(final String... keys);
+
+ /**
+ * Must be called before {@link AbstractTransaction#multi() MULTI}.
+ */
+ public abstract String watch(final byte[]... keys);
+
+ public abstract String unwatch();
+
+ @Override public abstract void close();
+
+ public abstract List