├── .editorconfig
├── .github
└── workflows
│ ├── build.yml
│ ├── release.yml
│ └── trigger-release.yml
├── .gitignore
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENSE
├── README.md
├── ci
├── .gitignore
├── after_success.sh
├── deploy-release.sh
├── deploy-snapshot.sh
├── dropwizard.asc.enc
└── settings.xml
├── mvnw
├── pom.xml
├── renovate.json
└── src
├── main
├── java
│ └── io
│ │ └── dropwizard
│ │ └── redis
│ │ ├── AbstractRedisClientFactory.java
│ │ ├── RedisClientBundle.java
│ │ ├── RedisClientFactory.java
│ │ ├── RedisClusterClientBundle.java
│ │ ├── RedisClusterClientFactory.java
│ │ ├── clientoptions
│ │ ├── ClientOptionsFactory.java
│ │ └── ClusterClientOptionsFactory.java
│ │ ├── clientresources
│ │ ├── ClientResourcesFactory.java
│ │ └── DefaultClientResourcesFactory.java
│ │ ├── codec
│ │ ├── ByteArrayCodecFactory.java
│ │ ├── CompressionCodecFactory.java
│ │ ├── RedisCodecFactory.java
│ │ ├── StringCodecFactory.java
│ │ └── Utf8StringCodecFactory.java
│ │ ├── delay
│ │ ├── ConstantDelayFactory.java
│ │ ├── DecorrelatedJitterDelayFactory.java
│ │ ├── DelayFactory.java
│ │ ├── EqualJitterDelayFactory.java
│ │ ├── ExponentialDelayFactory.java
│ │ └── FullJitterDelayFactory.java
│ │ ├── event
│ │ ├── DefaultEventBusFactory.java
│ │ ├── DefaultEventLoopGroupProviderFactory.java
│ │ ├── EventBusFactory.java
│ │ └── EventLoopGroupProviderFactory.java
│ │ ├── health
│ │ ├── Pingable.java
│ │ └── RedisHealthCheck.java
│ │ ├── managed
│ │ └── RedisClientManager.java
│ │ ├── metrics
│ │ ├── CommandLatencyRecorderFactory.java
│ │ ├── DefaultCommandLatencyCollectorFactory.java
│ │ ├── DefaultEventPublisherOptionsFactory.java
│ │ ├── DropwizardCommandLatencyRecorder.java
│ │ ├── DropwizardCommandLatencyRecorderFactory.java
│ │ ├── EventPublisherOptionsFactory.java
│ │ └── event
│ │ │ ├── LettuceMetricsSubscriber.java
│ │ │ ├── visitor
│ │ │ ├── ClusterTopologyChangedEventVisitor.java
│ │ │ ├── CommandLatencyEventVisitor.java
│ │ │ ├── ConnectedEventVisitor.java
│ │ │ ├── ConnectionActivatedEventVisitor.java
│ │ │ ├── ConnectionDeactivatedEventVisitor.java
│ │ │ ├── DisconnectedEventVisitor.java
│ │ │ └── EventVisitor.java
│ │ │ └── wrapper
│ │ │ ├── EventWrapperFactory.java
│ │ │ ├── VisitableClusterTopologyEventWrapper.java
│ │ │ ├── VisitableCommandLatencyEventWrapper.java
│ │ │ ├── VisitableConnectedEventWrapper.java
│ │ │ ├── VisitableConnectionActivatedEventWrapper.java
│ │ │ ├── VisitableConnectionDeactivatedEventWrapper.java
│ │ │ ├── VisitableDisconnectedEventWrapper.java
│ │ │ └── VisitableEventWrapper.java
│ │ ├── netty
│ │ ├── DefaultEventExecutorGroupFactory.java
│ │ └── EventExecutorGroupFactory.java
│ │ ├── socket
│ │ └── SocketOptionsFactory.java
│ │ ├── ssl
│ │ └── SslOptionsFactory.java
│ │ ├── timeout
│ │ └── TimeoutOptionsFactory.java
│ │ ├── topology
│ │ └── ClusterTopologyRefreshOptionsFactory.java
│ │ └── uri
│ │ ├── RedisModeURIFactory.java
│ │ ├── RedisURIFactory.java
│ │ └── SentinelModeURIFactory.java
└── resources
│ └── META-INF
│ └── services
│ ├── io.dropwizard.jackson.Discoverable
│ ├── io.dropwizard.redis.AbstractRedisClientFactory
│ ├── io.dropwizard.redis.clientresources.ClientResourcesFactory
│ ├── io.dropwizard.redis.codec.RedisCodecFactory
│ ├── io.dropwizard.redis.delay.DelayFactory
│ ├── io.dropwizard.redis.event.EventBusFactory
│ ├── io.dropwizard.redis.event.EventLoopGroupProviderFactory
│ ├── io.dropwizard.redis.metrics.CommandLatencyRecorderFactory
│ ├── io.dropwizard.redis.metrics.EventPublisherOptionsFactory
│ ├── io.dropwizard.redis.netty.EventExecutorGroupFactory
│ └── io.dropwizard.redis.uri.RedisURIFactory
└── test
├── java
└── io
│ └── dropwizard
│ └── redis
│ ├── clientoptions
│ └── ClusterClientOptionsFactoryTest.java
│ ├── clientresources
│ └── DefaultClientResourcesFactoryTest.java
│ ├── codec
│ ├── ByteArrayCodecFactoryTest.java
│ ├── CompressionCodecFactoryTest.java
│ ├── StringCodecFactoryTest.java
│ └── Utf8StringCodecFactoryTest.java
│ ├── delay
│ ├── ConstantDelayFactoryTest.java
│ ├── DecorrelatedJitterDelayFactoryTest.java
│ ├── EqualJitterDelayFactoryTest.java
│ ├── ExponentialDelayFactoryTest.java
│ └── FullJitterDelayFactoryTest.java
│ ├── event
│ ├── DefaultEventBusFactoryTest.java
│ └── DefaultEventLoopGroupProviderFactoryTest.java
│ ├── health
│ └── RedisHealthCheckTest.java
│ ├── managed
│ └── RedisClientManagerTest.java
│ ├── metrics
│ ├── DefaultCommandLatencyCollectorFactoryTest.java
│ ├── DefaultEventPublisherOptionsFactoryTest.java
│ ├── DropwizardCommandLatencyRecorderTest.java
│ └── event
│ │ └── LettuceMetricsSubscriberTest.java
│ ├── netty
│ └── DefaultEventExecutorGroupFactoryTest.java
│ ├── socket
│ └── SocketOptionsFactoryTest.java
│ ├── ssl
│ └── SslOptionsFactoryTest.java
│ ├── test
│ ├── RedisClusterBundleIT.java
│ ├── TestApplication.java
│ └── TestConfiguration.java
│ ├── timeout
│ └── TimeoutOptionsFactoryTest.java
│ ├── topology
│ └── ClusterTopologyRefreshOptionsFactoryTest.java
│ └── uri
│ ├── RedisModeURIFactoryTest.java
│ └── SentinelModeURIFactoryTest.java
└── resources
├── keystore.p12
├── truststore.p12
└── yaml
├── clientresources
└── default.yaml
├── codec
└── compression.yaml
├── config.yaml
├── delay
├── constant.yaml
├── decorrelated-jitter.yaml
├── equal-jitter.yaml
├── exponential.yaml
└── full-jitter.yaml
├── metrics
├── default-command-latency-collector.yaml
└── default-event-publisher.yaml
├── netty
└── default.yaml
├── socket
└── socket-options.yaml
├── ssl
└── ssl.yaml
├── timeout
└── timeout-options.yaml
├── topology
└── cluster-topology-refresh-options.yaml
└── uri
├── redis-uri.yaml
└── sentinel-redis-uri.yaml
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset=utf-8
3 | end_of_line=lf
4 | trim_trailing_whitespace=true
5 | max_line_length=120
6 | insert_final_newline=true
7 | indent_style=space
8 | indent_size=2
9 |
10 | [*.java]
11 | indent_style=space
12 | indent_size=4
13 | continuation_indent_size=8
14 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Build
3 | # yamllint disable-line rule:truthy
4 | on:
5 | push:
6 | branches:
7 | - release/*
8 | pull_request:
9 | jobs:
10 | yamllint:
11 | uses: dropwizard/workflows/.github/workflows/yamllint.yml@main
12 | build:
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | java-version: ['11', '17', '21']
17 | uses: dropwizard/workflows/.github/workflows/maven.yml@main
18 | secrets: inherit
19 | with:
20 | java-version: ${{ matrix.java-version }}
21 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Release
3 | # yamllint disable-line rule:truthy
4 | on:
5 | push:
6 | tags:
7 | - dropwizard-redis-*
8 | jobs:
9 | release:
10 | uses: dropwizard/workflows/.github/workflows/release.yml@main
11 | secrets: inherit
12 |
--------------------------------------------------------------------------------
/.github/workflows/trigger-release.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # yamllint disable rule:comments rule:line-length
3 | name: Trigger Release
4 | # yamllint disable-line rule:truthy
5 | on:
6 | workflow_dispatch:
7 | inputs:
8 | releaseVersion:
9 | description: Version of the next release
10 | required: true
11 | type: string
12 | developmentVersion:
13 | description: Version of the next development cycle (must end in "-SNAPSHOT")
14 | required: true
15 | type: string
16 | jobs:
17 | release:
18 | uses: dropwizard/workflows/.github/workflows/trigger-release.yml@main
19 | secrets: inherit
20 | with:
21 | releaseVersion: ${{ inputs.releaseVersion }}
22 | developmentVersion: ${{ inputs.developmentVersion }}
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .out
4 | out
5 | .dist
6 | .run
7 | .gradle
8 | target
9 | logs
10 |
11 | .idea
12 | *.iml
13 | *.ipr
14 | *.iws
15 | *.class
16 | *.log
17 |
18 | # eclipse
19 | .project
20 | .settings
21 | bin
22 | .classpath
23 |
24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
25 | hs_err_pid*
26 |
27 | */dependency-reduced-pom.xml
28 | node_modules
29 | .cache
30 |
31 | .vscode
32 | .factorypath
33 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dropwizard/dropwizard-redis/420d22b093e8b78539ba2bdffd403bfc33517f69/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.10/apache-maven-3.9.10-bin.zip
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dropwizard-redis
2 |
3 | Provides easy integration for Dropwizard applications with Redis via the Lettuce library.
4 |
5 | This bundle comes with out-of-the-box support for:
6 | * Configuration
7 | * Client lifecycle management
8 | * Client health checks
9 | * Dropwizard Metrics integration
10 | * Brave distributed tracing instrumentation integration for the Lettuce client.
11 | * Support for the Lettuce cluster client.
12 | * Support for the Lettuce sentinel client
13 | * Support the the Lettuce basic Redis client
14 |
15 | For more information on Redis, take a look at the official documentation here: https://redis.io/documentation
16 |
17 | For More information on the Redis client used (Lettuce), see: https://github.com/lettuce-io/lettuce-core
18 |
19 | ## Dropwizard Version Support Matrix
20 | | dropwizard-redis | Dropwizard v1.3.x | Dropwizard v2.0.x | Dropwizard v2.1.x | Dropwizard v3.0.x | Dropwizard v4.0.x |
21 | |------------------|--------------------|--------------------|--------------------|--------------------|--------------------|
22 | | v1.3.x | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: |
23 | | v1.4.x | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: |
24 | | v1.5.x | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: |
25 | | v1.6.x | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: |
26 | | v1.7.x | :white_check_mark: | :white_check_mark: | :question: | :x: | :x: |
27 | | v1.8.x | :x: | :question: | :white_check_mark: | :x: | :x: |
28 | | v3.0.x | :x: | :x: | :x: | :white_check_mark: | :x: |
29 | | v4.0.x | :x: | :x: | :x: | :x: | :white_check_mark: |
30 |
31 | ## Usage
32 | Add dependency on library.
33 |
34 | Maven:
35 | ```xml
36 |
37 | io.dropwizard.modules
38 | dropwizard-redis
39 | $latest-version
40 |
41 | ```
42 |
43 | Gradle:
44 | ```groovy
45 | compile "io.dropwizard.modules:dropwizard-redis:$latest-version"
46 | ```
47 |
48 |
49 | ### Basic Lettuce Client
50 | In your Dropwizard `Configuration` class, configure a `RedisClientFactory`:
51 | ```java
52 | @Valid
53 | @NotNull
54 | @JsonProperty("redis")
55 | private RedisClientFactory redisClientFactory;
56 | ```
57 |
58 | Then, in your `Application` class, you'll want to do something similar to the following:
59 | ```java
60 | private final RedisClientBundle redis = new RedisClientBundle() {
61 | @Override
62 | public RedisClientFactory getRedisClientFactory(ExampleConfiguration configuration) {
63 | return configuration.getRedisClientFactory();
64 | }
65 | };
66 |
67 | @Override
68 | public void initialize(Bootstrap bootstrap) {
69 | bootstrap.addBundle(redis);
70 | }
71 |
72 | @Override
73 | public void run(ExampleConfiguration config, Environment environment) {
74 | final StatefulRedisConnection connection = redisCluster.getConnection();
75 | final PersonCache personCache = new PersonCache(connection); // PersonCache is an arbtirary example
76 | environment.jersey().register(new PersonResource(personCache));
77 | }
78 | ```
79 |
80 |
81 | ```yaml
82 | redis:
83 | type: basic
84 | name: my-redis-use-case
85 | node:
86 | type: redis
87 | node: "127.0.0.1:6379"
88 | clientName: person-app
89 | redisCodec:
90 | type: string
91 | clientResources:
92 | type: default
93 | commandLatencyRecorder:
94 | type: default
95 | enabled: false
96 | ```
97 |
98 |
99 | ### Lettuce Cluster Client
100 | In your Dropwizard `Configuration` class, configure a `RedisClusterClientFactory`:
101 | ```java
102 | @Valid
103 | @NotNull
104 | @JsonProperty("redis-cluster")
105 | private RedisClusterClientFactory redisClientFactory;
106 | ```
107 |
108 | Then, in your `Application` class, you'll want to do something similar to the following:
109 | ```java
110 | private final RedisClusterClientBundle redisCluster = new RedisClusterClientBundle() {
111 | @Override
112 | public RedisClusterClientFactory getRedisClusterClientFactory(ExampleConfiguration configuration) {
113 | return configuration.getRedisClusterClientFactory();
114 | }
115 | };
116 |
117 | @Override
118 | public void initialize(Bootstrap bootstrap) {
119 | bootstrap.addBundle(redisCluster);
120 | }
121 |
122 | @Override
123 | public void run(ExampleConfiguration config, Environment environment) {
124 | final StatefulRedisClusterConnection clusterConnection = redisCluster.getClusterConnection();
125 | final PersonCache personCache = new PersonCache(clusterConnection); // PersonCache is an arbtirary example
126 | environment.jersey().register(new PersonResource(personCache));
127 | }
128 | ```
129 |
130 | Configure your factory in your `config.yml` file:
131 | ```yaml
132 | redis-cluster:
133 | type: cluster
134 | name: my-redis-cluster-use-case
135 | nodes:
136 | - type: redis
137 | node: "127.0.0.1:6379"
138 | clientName: person-app
139 | password: hunter2
140 | redisCodec:
141 | type: string
142 | clientResources:
143 | type: default
144 | commandLatencyRecorder:
145 | type: default
146 | enabled: false
147 | # TODO: add more configs than just the required basics
148 | ```
149 |
--------------------------------------------------------------------------------
/ci/.gitignore:
--------------------------------------------------------------------------------
1 | dropwizard.asc
2 |
--------------------------------------------------------------------------------
/ci/after_success.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -uxo pipefail
4 |
5 | if [[ "${TRAVIS_JDK_VERSION}" == "openjdk8" ]]; then
6 | # ./mvnw coveralls:report -B -q
7 | # exit $?
8 | fi
9 |
--------------------------------------------------------------------------------
/ci/deploy-release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -uxo pipefail
4 |
5 | # Decrypt and import signing key
6 | openssl aes-256-cbc -K $encrypted_57a5d69ebeaa_key -iv $encrypted_57a5d69ebeaa_iv -in ci/dropwizard.asc.enc -out ci/dropwizard.asc -d
7 | gpg --armor --import ci/dropwizard.asc
8 |
9 | ./mvnw -B deploy --settings 'ci/settings.xml' -DperformRelease=true -Dmaven.test.skip=true
10 |
--------------------------------------------------------------------------------
/ci/deploy-snapshot.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -uxo pipefail
4 |
5 | ./mvnw -B deploy --settings 'ci/settings.xml' -Dmaven.test.skip=true
6 |
--------------------------------------------------------------------------------
/ci/dropwizard.asc.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dropwizard/dropwizard-redis/420d22b093e8b78539ba2bdffd403bfc33517f69/ci/dropwizard.asc.enc
--------------------------------------------------------------------------------
/ci/settings.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 | ossrh
8 | ${env.CI_DEPLOY_USERNAME}
9 | ${env.CI_DEPLOY_PASSWORD}
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | #
58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look
59 | # for the new JDKs provided by Oracle.
60 | #
61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
62 | #
63 | # Apple JDKs
64 | #
65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
66 | fi
67 |
68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
69 | #
70 | # Apple JDKs
71 | #
72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
73 | fi
74 |
75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
76 | #
77 | # Oracle JDKs
78 | #
79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
80 | fi
81 |
82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
83 | #
84 | # Apple JDKs
85 | #
86 | export JAVA_HOME=`/usr/libexec/java_home`
87 | fi
88 | ;;
89 | esac
90 |
91 | if [ -z "$JAVA_HOME" ] ; then
92 | if [ -r /etc/gentoo-release ] ; then
93 | JAVA_HOME=`java-config --jre-home`
94 | fi
95 | fi
96 |
97 | if [ -z "$M2_HOME" ] ; then
98 | ## resolve links - $0 may be a link to maven's home
99 | PRG="$0"
100 |
101 | # need this for relative symlinks
102 | while [ -h "$PRG" ] ; do
103 | ls=`ls -ld "$PRG"`
104 | link=`expr "$ls" : '.*-> \(.*\)$'`
105 | if expr "$link" : '/.*' > /dev/null; then
106 | PRG="$link"
107 | else
108 | PRG="`dirname "$PRG"`/$link"
109 | fi
110 | done
111 |
112 | saveddir=`pwd`
113 |
114 | M2_HOME=`dirname "$PRG"`/..
115 |
116 | # make it fully qualified
117 | M2_HOME=`cd "$M2_HOME" && pwd`
118 |
119 | cd "$saveddir"
120 | # echo Using m2 at $M2_HOME
121 | fi
122 |
123 | # For Cygwin, ensure paths are in UNIX format before anything is touched
124 | if $cygwin ; then
125 | [ -n "$M2_HOME" ] &&
126 | M2_HOME=`cygpath --unix "$M2_HOME"`
127 | [ -n "$JAVA_HOME" ] &&
128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
129 | [ -n "$CLASSPATH" ] &&
130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
131 | fi
132 |
133 | # For Migwn, ensure paths are in UNIX format before anything is touched
134 | if $mingw ; then
135 | [ -n "$M2_HOME" ] &&
136 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
137 | [ -n "$JAVA_HOME" ] &&
138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
139 | # TODO classpath?
140 | fi
141 |
142 | if [ -z "$JAVA_HOME" ]; then
143 | javaExecutable="`which javac`"
144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
145 | # readlink(1) is not available as standard on Solaris 10.
146 | readLink=`which readlink`
147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
148 | if $darwin ; then
149 | javaHome="`dirname \"$javaExecutable\"`"
150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
151 | else
152 | javaExecutable="`readlink -f \"$javaExecutable\"`"
153 | fi
154 | javaHome="`dirname \"$javaExecutable\"`"
155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
156 | JAVA_HOME="$javaHome"
157 | export JAVA_HOME
158 | fi
159 | fi
160 | fi
161 |
162 | if [ -z "$JAVACMD" ] ; then
163 | if [ -n "$JAVA_HOME" ] ; then
164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
165 | # IBM's JDK on AIX uses strange locations for the executables
166 | JAVACMD="$JAVA_HOME/jre/sh/java"
167 | else
168 | JAVACMD="$JAVA_HOME/bin/java"
169 | fi
170 | else
171 | JAVACMD="`which java`"
172 | fi
173 | fi
174 |
175 | if [ ! -x "$JAVACMD" ] ; then
176 | echo "Error: JAVA_HOME is not defined correctly." >&2
177 | echo " We cannot execute $JAVACMD" >&2
178 | exit 1
179 | fi
180 |
181 | if [ -z "$JAVA_HOME" ] ; then
182 | echo "Warning: JAVA_HOME environment variable is not set."
183 | fi
184 |
185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
186 |
187 | # traverses directory structure from process work directory to filesystem root
188 | # first directory with .mvn subdirectory is considered project base directory
189 | find_maven_basedir() {
190 | local basedir=$(pwd)
191 | local wdir=$(pwd)
192 | while [ "$wdir" != '/' ] ; do
193 | if [ -d "$wdir"/.mvn ] ; then
194 | basedir=$wdir
195 | break
196 | fi
197 | wdir=$(cd "$wdir/.."; pwd)
198 | done
199 | echo "${basedir}"
200 | }
201 |
202 | # concatenates all lines of a file
203 | concat_lines() {
204 | if [ -f "$1" ]; then
205 | echo "$(tr -s '\n' ' ' < "$1")"
206 | fi
207 | }
208 |
209 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
210 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
211 |
212 | # For Cygwin, switch paths to Windows format before running java
213 | if $cygwin; then
214 | [ -n "$M2_HOME" ] &&
215 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
216 | [ -n "$JAVA_HOME" ] &&
217 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
218 | [ -n "$CLASSPATH" ] &&
219 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
220 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
221 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
222 | fi
223 |
224 | # Provide a "standardized" way to retrieve the CLI args that will
225 | # work with both Windows and non-Windows executions.
226 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
227 | export MAVEN_CMD_LINE_ARGS
228 |
229 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
230 |
231 | # avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in $@
232 | exec "$JAVACMD" \
233 | $MAVEN_OPTS \
234 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
235 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
236 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
237 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 | io.dropwizard.modules
7 | module-parent
8 | 4.0.4
9 |
10 | io.dropwizard.modules
11 | dropwizard-redis
12 | 4.0.1-SNAPSHOT
13 | jar
14 |
15 | Dropwizard Redis
16 | Provides easy integration for Dropwizard applications with Redis
17 |
18 |
19 |
20 | dropwizard-redis
21 | http://dropwizard.github.io/dropwizard-redis/${project.version}
22 |
23 |
24 |
25 |
26 |
27 | nzamani1
28 | Natalie Zamani
29 | natalie.zamani@apple.com
30 |
31 |
32 |
33 |
34 | dropwizard_dropwizard-redis
35 |
36 | 6.3.0
37 | 6.7.1.RELEASE
38 | 1.1.11
39 |
40 |
41 |
42 |
43 | io.dropwizard
44 | dropwizard-core
45 |
46 |
47 | io.lettuce
48 | lettuce-core
49 | ${lettuce.version}
50 |
51 |
52 | io.zipkin.brave
53 | brave
54 | ${brave.version}
55 |
56 |
57 |
58 |
59 | org.junit.jupiter
60 | junit-jupiter
61 | test
62 |
63 |
64 | org.mockito
65 | mockito-core
66 | test
67 |
68 |
69 | io.dropwizard
70 | dropwizard-testing
71 | test
72 |
73 |
74 | com.github.fppt
75 | jedis-mock
76 | ${redis-mock.version}
77 | test
78 |
79 |
80 | org.assertj
81 | assertj-core
82 | test
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | org.sonarsource.scanner.maven
91 | sonar-maven-plugin
92 | 5.1.0.4751
93 |
94 |
95 | org.jacoco
96 | jacoco-maven-plugin
97 | 0.8.13
98 |
99 |
100 |
101 |
102 |
103 | org.apache.maven.plugins
104 | maven-compiler-plugin
105 | 3.14.0
106 |
107 | 8
108 |
109 |
110 |
111 | org.jacoco
112 | jacoco-maven-plugin
113 |
114 |
115 | prepare-agent
116 |
117 | prepare-agent
118 |
119 |
120 |
121 | report
122 |
123 | report
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | kr.motd.maven
132 | os-maven-plugin
133 | 1.7.1
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "local>dropwizard/renovate-config"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/AbstractRedisClientFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis;
2 |
3 | import brave.Tracing;
4 | import com.codahale.metrics.MetricRegistry;
5 | import com.codahale.metrics.health.HealthCheckRegistry;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
8 | import com.google.common.collect.ImmutableList;
9 | import io.dropwizard.jackson.Discoverable;
10 | import io.dropwizard.lifecycle.setup.LifecycleEnvironment;
11 | import io.dropwizard.redis.clientresources.ClientResourcesFactory;
12 | import io.dropwizard.redis.clientresources.DefaultClientResourcesFactory;
13 | import io.dropwizard.redis.codec.RedisCodecFactory;
14 | import io.dropwizard.redis.metrics.event.visitor.ClusterTopologyChangedEventVisitor;
15 | import io.dropwizard.redis.metrics.event.visitor.CommandLatencyEventVisitor;
16 | import io.dropwizard.redis.metrics.event.visitor.ConnectedEventVisitor;
17 | import io.dropwizard.redis.metrics.event.visitor.ConnectionActivatedEventVisitor;
18 | import io.dropwizard.redis.metrics.event.visitor.ConnectionDeactivatedEventVisitor;
19 | import io.dropwizard.redis.metrics.event.visitor.DisconnectedEventVisitor;
20 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
21 | import io.lettuce.core.api.StatefulConnection;
22 | import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
23 | import org.checkerframework.checker.nullness.qual.Nullable;
24 |
25 | import java.util.List;
26 |
27 | import jakarta.validation.Valid;
28 | import jakarta.validation.constraints.NotNull;
29 |
30 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
31 | public abstract class AbstractRedisClientFactory implements Discoverable {
32 | @NotNull
33 | @JsonProperty
34 | protected String name;
35 |
36 | @Valid
37 | @JsonProperty
38 | protected ClusterTopologyRefreshOptions clusterTopologyRefreshOptions;
39 |
40 | @Valid
41 | @NotNull
42 | @JsonProperty
43 | protected ClientResourcesFactory clientResources = new DefaultClientResourcesFactory();
44 |
45 | @Valid
46 | @NotNull
47 | @JsonProperty
48 | protected RedisCodecFactory redisCodec;
49 |
50 | public String getName() {
51 | return name;
52 | }
53 |
54 | public void setName(final String name) {
55 | this.name = name;
56 | }
57 |
58 | public ClusterTopologyRefreshOptions getClusterTopologyRefreshOptions() {
59 | return clusterTopologyRefreshOptions;
60 | }
61 |
62 | public void setClusterTopologyRefreshOptions(final ClusterTopologyRefreshOptions clusterTopologyRefreshOptions) {
63 | this.clusterTopologyRefreshOptions = clusterTopologyRefreshOptions;
64 | }
65 |
66 | public ClientResourcesFactory getClientResources() {
67 | return clientResources;
68 | }
69 |
70 | public void setClientResources(final ClientResourcesFactory clientResources) {
71 | this.clientResources = clientResources;
72 | }
73 |
74 | public RedisCodecFactory getRedisCodec() {
75 | return redisCodec;
76 | }
77 |
78 | public void setRedisCodec(final RedisCodecFactory redisCodec) {
79 | this.redisCodec = redisCodec;
80 | }
81 |
82 | public StatefulConnection build(final HealthCheckRegistry healthChecks, final LifecycleEnvironment lifecycle,
83 | final MetricRegistry metrics) {
84 | return build(healthChecks, lifecycle, metrics, null);
85 | }
86 |
87 | public abstract StatefulConnection build(final HealthCheckRegistry healthChecks, final LifecycleEnvironment lifecycle,
88 | final MetricRegistry metrics, @Nullable final Tracing tracing);
89 |
90 | protected List buildEventVisitors(final MetricRegistry metrics) {
91 | // Extract this, and the event wrapper builders, to Dropwizard factories, if more event types are added frequently enough?
92 | return ImmutableList.of(
93 | new ClusterTopologyChangedEventVisitor(name, metrics),
94 | new CommandLatencyEventVisitor(name, metrics),
95 | new ConnectedEventVisitor(name, metrics),
96 | new ConnectionActivatedEventVisitor(name, metrics),
97 | new ConnectionDeactivatedEventVisitor(name, metrics),
98 | new DisconnectedEventVisitor(name, metrics)
99 | );
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/RedisClientBundle.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis;
2 |
3 | import brave.Tracing;
4 | import io.dropwizard.core.Configuration;
5 | import io.dropwizard.core.ConfiguredBundle;
6 | import io.dropwizard.core.setup.Bootstrap;
7 | import io.dropwizard.core.setup.Environment;
8 | import io.lettuce.core.api.StatefulRedisConnection;
9 | import org.checkerframework.checker.nullness.qual.Nullable;
10 |
11 | import static java.util.Objects.requireNonNull;
12 |
13 | public abstract class RedisClientBundle implements ConfiguredBundle {
14 | @Nullable
15 | private StatefulRedisConnection connection;
16 |
17 | @Override
18 | public void initialize(final Bootstrap> bootstrap) {
19 | // do nothing
20 | }
21 |
22 | @Override
23 | public void run(final T configuration, final Environment environment) throws Exception {
24 | final RedisClientFactory redisClientFactory = requireNonNull(getRedisClientFactory(configuration));
25 |
26 | final Tracing tracing = Tracing.current();
27 |
28 | this.connection = redisClientFactory.build(environment.healthChecks(), environment.lifecycle(), environment.metrics(), tracing);
29 | }
30 |
31 | public abstract RedisClientFactory getRedisClientFactory(T configuration);
32 |
33 | public StatefulRedisConnection getConnection() {
34 | return requireNonNull(connection);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/RedisClientFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis;
2 |
3 | import brave.Tracing;
4 | import com.codahale.metrics.MetricRegistry;
5 | import com.codahale.metrics.health.HealthCheckRegistry;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import com.fasterxml.jackson.annotation.JsonTypeName;
8 | import io.dropwizard.lifecycle.setup.LifecycleEnvironment;
9 | import io.dropwizard.redis.clientoptions.ClientOptionsFactory;
10 | import io.dropwizard.redis.health.RedisHealthCheck;
11 | import io.dropwizard.redis.managed.RedisClientManager;
12 | import io.dropwizard.redis.metrics.event.LettuceMetricsSubscriber;
13 | import io.dropwizard.redis.uri.RedisURIFactory;
14 | import io.lettuce.core.RedisClient;
15 | import io.lettuce.core.RedisURI;
16 | import io.lettuce.core.api.StatefulRedisConnection;
17 | import io.lettuce.core.codec.RedisCodec;
18 | import io.lettuce.core.resource.ClientResources;
19 |
20 | import jakarta.validation.Valid;
21 | import jakarta.validation.constraints.NotNull;
22 |
23 | @JsonTypeName("basic")
24 | public class RedisClientFactory extends AbstractRedisClientFactory {
25 | @Valid
26 | @NotNull
27 | @JsonProperty
28 | private RedisURIFactory node;
29 |
30 | @Valid
31 | @NotNull
32 | @JsonProperty
33 | private ClientOptionsFactory clientOptions = new ClientOptionsFactory();
34 |
35 | @Override
36 | public StatefulRedisConnection build(final HealthCheckRegistry healthChecks, final LifecycleEnvironment lifecycle,
37 | final MetricRegistry metrics) {
38 | return build(healthChecks, lifecycle, metrics, null);
39 | }
40 |
41 | @Override
42 | public StatefulRedisConnection build(final HealthCheckRegistry healthChecks, final LifecycleEnvironment lifecycle,
43 | final MetricRegistry metrics, final Tracing tracing) {
44 | final RedisURI uri = node.build();
45 |
46 | final ClientResources resources = clientResources.build(name, metrics, tracing);
47 |
48 | final RedisClient redisClient = RedisClient.create(resources, uri);
49 |
50 | redisClient.setOptions(clientOptions.build());
51 |
52 | final RedisCodec codec = redisCodec.build();
53 |
54 | final StatefulRedisConnection connection = redisClient.connect(codec);
55 |
56 | // manage client and connection
57 | lifecycle.manage(new RedisClientManager(redisClient, connection, name));
58 |
59 | // health check
60 | healthChecks.register(name, new RedisHealthCheck(() -> connection.sync().ping()));
61 |
62 | // metrics (latency and other connection events) integration
63 | redisClient.getResources()
64 | .eventBus()
65 | .get()
66 | .subscribe(new LettuceMetricsSubscriber(buildEventVisitors(metrics)));
67 |
68 | return connection;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/RedisClusterClientBundle.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis;
2 |
3 | import brave.Tracing;
4 | import io.dropwizard.core.Configuration;
5 | import io.dropwizard.core.ConfiguredBundle;
6 | import io.dropwizard.core.setup.Bootstrap;
7 | import io.dropwizard.core.setup.Environment;
8 | import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
9 | import org.checkerframework.checker.nullness.qual.Nullable;
10 |
11 | import static java.util.Objects.requireNonNull;
12 |
13 | public abstract class RedisClusterClientBundle implements ConfiguredBundle {
14 | @Nullable
15 | private StatefulRedisClusterConnection clusterConnection;
16 |
17 | @Override
18 | public void initialize(final Bootstrap> bootstrap) {
19 | // do nothing
20 | }
21 |
22 | @Override
23 | public void run(final T configuration, final Environment environment) throws Exception {
24 | final RedisClusterClientFactory redisClusterClientFactory = requireNonNull(getRedisClusterClientFactory(configuration));
25 |
26 | final Tracing tracing = Tracing.current();
27 |
28 | this.clusterConnection = redisClusterClientFactory.build(environment.healthChecks(), environment.lifecycle(), environment.metrics(),
29 | tracing);
30 | }
31 |
32 | public abstract RedisClusterClientFactory getRedisClusterClientFactory(T configuration);
33 |
34 | public StatefulRedisClusterConnection getClusterConnection() {
35 | return requireNonNull(clusterConnection);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/RedisClusterClientFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis;
2 |
3 | import brave.Tracing;
4 | import com.codahale.metrics.MetricRegistry;
5 | import com.codahale.metrics.health.HealthCheckRegistry;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import com.fasterxml.jackson.annotation.JsonTypeName;
8 | import io.dropwizard.lifecycle.setup.LifecycleEnvironment;
9 | import io.dropwizard.redis.clientoptions.ClusterClientOptionsFactory;
10 | import io.dropwizard.redis.health.RedisHealthCheck;
11 | import io.dropwizard.redis.managed.RedisClientManager;
12 | import io.dropwizard.redis.metrics.event.LettuceMetricsSubscriber;
13 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
14 | import io.dropwizard.redis.uri.RedisURIFactory;
15 | import io.lettuce.core.RedisURI;
16 | import io.lettuce.core.cluster.RedisClusterClient;
17 | import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
18 | import io.lettuce.core.codec.RedisCodec;
19 | import io.lettuce.core.resource.ClientResources;
20 | import org.checkerframework.checker.nullness.qual.Nullable;
21 | import org.hibernate.validator.constraints.NotEmpty;
22 |
23 | import jakarta.validation.Valid;
24 | import jakarta.validation.constraints.NotNull;
25 | import java.util.Collections;
26 | import java.util.List;
27 | import java.util.stream.Collectors;
28 |
29 | @JsonTypeName("cluster")
30 | public class RedisClusterClientFactory extends AbstractRedisClientFactory {
31 | @Valid
32 | @NotEmpty
33 | @JsonProperty
34 | private List nodes = Collections.emptyList();
35 |
36 | @Valid
37 | @NotNull
38 | @JsonProperty
39 | private ClusterClientOptionsFactory clientOptions = new ClusterClientOptionsFactory();
40 |
41 | public ClusterClientOptionsFactory getClientOptions() {
42 | return clientOptions;
43 | }
44 |
45 | public void setClientOptions(final ClusterClientOptionsFactory clientOptions) {
46 | this.clientOptions = clientOptions;
47 | }
48 |
49 | @Override
50 | public StatefulRedisClusterConnection build(final HealthCheckRegistry healthChecks, final LifecycleEnvironment lifecycle,
51 | final MetricRegistry metrics) {
52 | return build(healthChecks, lifecycle, metrics, null);
53 | }
54 |
55 | @Override
56 | public StatefulRedisClusterConnection build(final HealthCheckRegistry healthChecks, final LifecycleEnvironment lifecycle,
57 | final MetricRegistry metrics, @Nullable final Tracing tracing) {
58 | final List uris = nodes.stream()
59 | .map(RedisURIFactory::build)
60 | .collect(Collectors.toList());
61 |
62 | final ClientResources resources = clientResources.build(name, metrics, tracing);
63 |
64 | final RedisClusterClient redisClusterClient = RedisClusterClient.create(resources, uris);
65 |
66 | redisClusterClient.setOptions(clientOptions.build());
67 |
68 | final RedisCodec codec = redisCodec.build();
69 |
70 | final StatefulRedisClusterConnection connection = redisClusterClient.connect(codec);
71 |
72 | // manage client and connection
73 | lifecycle.manage(new RedisClientManager(redisClusterClient, connection, name));
74 |
75 | // health check
76 | healthChecks.register(name, new RedisHealthCheck(() -> connection.sync().ping()));
77 |
78 | // metrics (latency and other connection events) integration
79 | final List eventVisitors = buildEventVisitors(metrics);
80 | redisClusterClient.getResources()
81 | .eventBus()
82 | .get()
83 | .subscribe(new LettuceMetricsSubscriber(buildEventVisitors(metrics)));
84 |
85 | return connection;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/clientoptions/ClientOptionsFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.clientoptions;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import io.dropwizard.redis.socket.SocketOptionsFactory;
5 | import io.dropwizard.redis.ssl.SslOptionsFactory;
6 | import io.dropwizard.redis.timeout.TimeoutOptionsFactory;
7 | import io.lettuce.core.ClientOptions;
8 |
9 | import jakarta.validation.Valid;
10 | import jakarta.validation.constraints.Min;
11 | import jakarta.validation.constraints.NotNull;
12 |
13 | public class ClientOptionsFactory {
14 | @JsonProperty
15 | protected boolean pingBeforeActivateConnection = ClientOptions.DEFAULT_PING_BEFORE_ACTIVATE_CONNECTION;
16 |
17 | @JsonProperty
18 | protected boolean cancelCommandsOnReconnectFailure = ClientOptions.DEFAULT_CANCEL_CMD_RECONNECT_FAIL;
19 |
20 | @JsonProperty
21 | protected boolean publishOnScheduler = ClientOptions.DEFAULT_PUBLISH_ON_SCHEDULER;
22 |
23 | @JsonProperty
24 | protected boolean autoReconnect = ClientOptions.DEFAULT_AUTO_RECONNECT;
25 |
26 | @JsonProperty
27 | protected boolean suspendReconnectOnProtocolFailure = ClientOptions.DEFAULT_SUSPEND_RECONNECT_PROTO_FAIL;
28 |
29 | @Min(0)
30 | @JsonProperty
31 | protected int requestQueueSize = ClientOptions.DEFAULT_REQUEST_QUEUE_SIZE;
32 |
33 | @NotNull
34 | @JsonProperty
35 | protected ClientOptions.DisconnectedBehavior disconnectedBehavior = ClientOptions.DEFAULT_DISCONNECTED_BEHAVIOR;
36 |
37 | @Valid
38 | @NotNull
39 | @JsonProperty
40 | protected SocketOptionsFactory socketOptions = new SocketOptionsFactory();
41 |
42 | @Valid
43 | @JsonProperty
44 | protected SslOptionsFactory sslOptions;
45 |
46 | @Valid
47 | @NotNull
48 | @JsonProperty
49 | protected TimeoutOptionsFactory timeoutOptions = new TimeoutOptionsFactory();
50 |
51 | public boolean isPingBeforeActivateConnection() {
52 | return pingBeforeActivateConnection;
53 | }
54 |
55 | public void setPingBeforeActivateConnection(final boolean pingBeforeActivateConnection) {
56 | this.pingBeforeActivateConnection = pingBeforeActivateConnection;
57 | }
58 |
59 | public boolean isCancelCommandsOnReconnectFailure() {
60 | return cancelCommandsOnReconnectFailure;
61 | }
62 |
63 | public void setCancelCommandsOnReconnectFailure(final boolean cancelCommandsOnReconnectFailure) {
64 | this.cancelCommandsOnReconnectFailure = cancelCommandsOnReconnectFailure;
65 | }
66 |
67 | public boolean isPublishOnScheduler() {
68 | return publishOnScheduler;
69 | }
70 |
71 | public void setPublishOnScheduler(final boolean publishOnScheduler) {
72 | this.publishOnScheduler = publishOnScheduler;
73 | }
74 |
75 | public boolean isAutoReconnect() {
76 | return autoReconnect;
77 | }
78 |
79 | public void setAutoReconnect(final boolean autoReconnect) {
80 | this.autoReconnect = autoReconnect;
81 | }
82 |
83 | public boolean isSuspendReconnectOnProtocolFailure() {
84 | return suspendReconnectOnProtocolFailure;
85 | }
86 |
87 | public void setSuspendReconnectOnProtocolFailure(final boolean suspendReconnectOnProtocolFailure) {
88 | this.suspendReconnectOnProtocolFailure = suspendReconnectOnProtocolFailure;
89 | }
90 |
91 | public int getRequestQueueSize() {
92 | return requestQueueSize;
93 | }
94 |
95 | public void setRequestQueueSize(final int requestQueueSize) {
96 | this.requestQueueSize = requestQueueSize;
97 | }
98 |
99 | public ClientOptions.DisconnectedBehavior getDisconnectedBehavior() {
100 | return disconnectedBehavior;
101 | }
102 |
103 | public void setDisconnectedBehavior(final ClientOptions.DisconnectedBehavior disconnectedBehavior) {
104 | this.disconnectedBehavior = disconnectedBehavior;
105 | }
106 |
107 | public SocketOptionsFactory getSocketOptions() {
108 | return socketOptions;
109 | }
110 |
111 | public void setSocketOptions(final SocketOptionsFactory socketOptions) {
112 | this.socketOptions = socketOptions;
113 | }
114 |
115 | public SslOptionsFactory getSslOptions() {
116 | return sslOptions;
117 | }
118 |
119 | public void setSslOptions(final SslOptionsFactory sslOptions) {
120 | this.sslOptions = sslOptions;
121 | }
122 |
123 | public TimeoutOptionsFactory getTimeoutOptions() {
124 | return timeoutOptions;
125 | }
126 |
127 | public void setTimeoutOptions(final TimeoutOptionsFactory timeoutOptions) {
128 | this.timeoutOptions = timeoutOptions;
129 | }
130 |
131 | public ClientOptions build() {
132 | final ClientOptions.Builder builder = ClientOptions.builder();
133 |
134 | return addBuildParams(builder).build();
135 | }
136 |
137 | protected ClientOptions.Builder addBuildParams(final ClientOptions.Builder builder) {
138 | builder.pingBeforeActivateConnection(pingBeforeActivateConnection)
139 | .cancelCommandsOnReconnectFailure(cancelCommandsOnReconnectFailure)
140 | .publishOnScheduler(publishOnScheduler)
141 | .autoReconnect(autoReconnect)
142 | .suspendReconnectOnProtocolFailure(suspendReconnectOnProtocolFailure)
143 | .requestQueueSize(requestQueueSize)
144 | .disconnectedBehavior(disconnectedBehavior)
145 | .socketOptions(socketOptions.build())
146 | .timeoutOptions(timeoutOptions.build());
147 |
148 | if (sslOptions != null && sslOptions.isEnabled()) {
149 | builder.sslOptions(sslOptions.build());
150 | }
151 |
152 | return builder;
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/clientoptions/ClusterClientOptionsFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.clientoptions;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import io.dropwizard.redis.topology.ClusterTopologyRefreshOptionsFactory;
5 | import io.lettuce.core.cluster.ClusterClientOptions;
6 | import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
7 |
8 | import jakarta.validation.Valid;
9 | import jakarta.validation.constraints.Min;
10 |
11 | public class ClusterClientOptionsFactory extends ClientOptionsFactory {
12 | @JsonProperty
13 | private boolean validateClusterNodeMembership = ClusterClientOptions.DEFAULT_VALIDATE_CLUSTER_MEMBERSHIP;
14 |
15 | @Min(0)
16 | @JsonProperty
17 | private int maxRedirects = ClusterClientOptions.DEFAULT_MAX_REDIRECTS;
18 |
19 | @Valid
20 | @JsonProperty
21 | private ClusterTopologyRefreshOptionsFactory topologyRefreshOptions;
22 |
23 | public boolean isValidateClusterNodeMembership() {
24 | return validateClusterNodeMembership;
25 | }
26 |
27 | public void setValidateClusterNodeMembership(final boolean validateClusterNodeMembership) {
28 | this.validateClusterNodeMembership = validateClusterNodeMembership;
29 | }
30 |
31 | public int getMaxRedirects() {
32 | return maxRedirects;
33 | }
34 |
35 | public void setMaxRedirects(final int maxRedirects) {
36 | this.maxRedirects = maxRedirects;
37 | }
38 |
39 | public ClusterTopologyRefreshOptionsFactory getTopologyRefreshOptions() {
40 | return topologyRefreshOptions;
41 | }
42 |
43 | public void setTopologyRefreshOptions(final ClusterTopologyRefreshOptionsFactory topologyRefreshOptions) {
44 | this.topologyRefreshOptions = topologyRefreshOptions;
45 | }
46 |
47 | @Override
48 | public ClusterClientOptions build() {
49 | final ClusterClientOptions.Builder builder = ((ClusterClientOptions.Builder) super.addBuildParams(ClusterClientOptions.builder()))
50 | .validateClusterNodeMembership(validateClusterNodeMembership)
51 | .maxRedirects(maxRedirects);
52 |
53 | if (topologyRefreshOptions != null) {
54 | final ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = topologyRefreshOptions.build();
55 | builder.topologyRefreshOptions(clusterTopologyRefreshOptions);
56 | }
57 |
58 | return builder.build();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/clientresources/ClientResourcesFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.clientresources;
2 |
3 | import brave.Tracing;
4 | import com.codahale.metrics.MetricRegistry;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
7 | import io.dropwizard.jackson.Discoverable;
8 | import io.dropwizard.redis.delay.DelayFactory;
9 | import io.dropwizard.redis.delay.ExponentialDelayFactory;
10 | import io.dropwizard.redis.event.DefaultEventBusFactory;
11 | import io.dropwizard.redis.event.DefaultEventLoopGroupProviderFactory;
12 | import io.dropwizard.redis.event.EventBusFactory;
13 | import io.dropwizard.redis.event.EventLoopGroupProviderFactory;
14 | import io.dropwizard.redis.metrics.CommandLatencyRecorderFactory;
15 | import io.dropwizard.redis.metrics.DefaultCommandLatencyCollectorFactory;
16 | import io.dropwizard.redis.metrics.DefaultEventPublisherOptionsFactory;
17 | import io.dropwizard.redis.metrics.EventPublisherOptionsFactory;
18 | import io.dropwizard.redis.netty.DefaultEventExecutorGroupFactory;
19 | import io.dropwizard.redis.netty.EventExecutorGroupFactory;
20 | import io.lettuce.core.resource.ClientResources;
21 | import io.lettuce.core.resource.DefaultClientResources;
22 | import org.checkerframework.checker.nullness.qual.Nullable;
23 |
24 | import jakarta.validation.Valid;
25 | import jakarta.validation.constraints.Min;
26 | import jakarta.validation.constraints.NotNull;
27 |
28 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
29 | public abstract class ClientResourcesFactory implements Discoverable {
30 | @Valid
31 | @NotNull
32 | @JsonProperty
33 | protected CommandLatencyRecorderFactory commandLatencyRecorder = new DefaultCommandLatencyCollectorFactory();
34 |
35 | @Valid
36 | @NotNull
37 | @JsonProperty
38 | protected EventPublisherOptionsFactory eventPublisherOptions = new DefaultEventPublisherOptionsFactory();
39 |
40 | @Valid
41 | @NotNull
42 | @JsonProperty
43 | protected EventBusFactory eventBusFactory = new DefaultEventBusFactory();
44 |
45 | @Valid
46 | @NotNull
47 | @JsonProperty
48 | protected EventExecutorGroupFactory eventExecutorGroup = new DefaultEventExecutorGroupFactory();
49 |
50 | @Valid
51 | @NotNull
52 | @JsonProperty
53 | protected EventLoopGroupProviderFactory eventLoopGroupProvider = new DefaultEventLoopGroupProviderFactory();
54 |
55 | @Min(1)
56 | @JsonProperty
57 | protected int computationThreads = DefaultClientResources.DEFAULT_COMPUTATION_THREADS;
58 |
59 | @Min(1)
60 | @JsonProperty
61 | protected int ioThreads = DefaultClientResources.DEFAULT_IO_THREADS;
62 |
63 | @Valid
64 | @NotNull
65 | protected DelayFactory delay = new ExponentialDelayFactory();
66 |
67 | public CommandLatencyRecorderFactory getCommandLatencyRecorder() {
68 | return commandLatencyRecorder;
69 | }
70 |
71 | public void setCommandLatencyRecorder(final CommandLatencyRecorderFactory commandLatencyRecorder) {
72 | this.commandLatencyRecorder = commandLatencyRecorder;
73 | }
74 |
75 | public EventPublisherOptionsFactory getEventPublisherOptions() {
76 | return eventPublisherOptions;
77 | }
78 |
79 | public void setEventPublisherOptions(final EventPublisherOptionsFactory eventPublisherOptions) {
80 | this.eventPublisherOptions = eventPublisherOptions;
81 | }
82 |
83 | public EventBusFactory getEventBusFactory() {
84 | return eventBusFactory;
85 | }
86 |
87 | public void setEventBusFactory(final EventBusFactory eventBusFactory) {
88 | this.eventBusFactory = eventBusFactory;
89 | }
90 |
91 | public EventExecutorGroupFactory getEventExecutorGroup() {
92 | return eventExecutorGroup;
93 | }
94 |
95 | public void setEventExecutorGroup(final EventExecutorGroupFactory eventExecutorGroup) {
96 | this.eventExecutorGroup = eventExecutorGroup;
97 | }
98 |
99 | public EventLoopGroupProviderFactory getEventLoopGroupProvider() {
100 | return eventLoopGroupProvider;
101 | }
102 |
103 | public void setEventLoopGroupProvider(final EventLoopGroupProviderFactory eventLoopGroupProvider) {
104 | this.eventLoopGroupProvider = eventLoopGroupProvider;
105 | }
106 |
107 | public int getComputationThreads() {
108 | return computationThreads;
109 | }
110 |
111 | public void setComputationThreads(final int computationThreads) {
112 | this.computationThreads = computationThreads;
113 | }
114 |
115 | public int getIoThreads() {
116 | return ioThreads;
117 | }
118 |
119 | public void setIoThreads(final int ioThreads) {
120 | this.ioThreads = ioThreads;
121 | }
122 |
123 | public DelayFactory getDelay() {
124 | return delay;
125 | }
126 |
127 | public void setDelay(final DelayFactory delay) {
128 | this.delay = delay;
129 | }
130 |
131 | public abstract ClientResources build(final String name, final MetricRegistry metrics, @Nullable final Tracing tracing);
132 | }
133 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/clientresources/DefaultClientResourcesFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.clientresources;
2 |
3 | import brave.Tracing;
4 | import com.codahale.metrics.MetricRegistry;
5 | import com.fasterxml.jackson.annotation.JsonTypeName;
6 | import io.lettuce.core.resource.ClientResources;
7 | import io.lettuce.core.resource.DefaultClientResources;
8 | import io.lettuce.core.tracing.BraveTracing;
9 | import io.netty.util.concurrent.EventExecutorGroup;
10 | import org.checkerframework.checker.nullness.qual.Nullable;
11 | import reactor.core.scheduler.Schedulers;
12 |
13 | @JsonTypeName("default")
14 | public class DefaultClientResourcesFactory extends ClientResourcesFactory {
15 | @Override
16 | public ClientResources build(final String name, final MetricRegistry metrics, @Nullable final Tracing tracing) {
17 | final EventExecutorGroup executorGroup = eventExecutorGroup.build(computationThreads, name, metrics);
18 |
19 | final ClientResources.Builder builder = DefaultClientResources.builder()
20 | .commandLatencyRecorder(commandLatencyRecorder.build(metrics))
21 | .commandLatencyPublisherOptions(eventPublisherOptions.build())
22 | .eventExecutorGroup(executorGroup)
23 | .eventBus(eventBusFactory.build(Schedulers.fromExecutor(executorGroup)))
24 | .computationThreadPoolSize(computationThreads)
25 | .ioThreadPoolSize(ioThreads)
26 | .eventLoopGroupProvider(eventLoopGroupProvider.build(computationThreads))
27 | .reconnectDelay(delay.build());
28 |
29 | if (tracing != null) {
30 | builder.tracing(BraveTracing.create(tracing));
31 | }
32 |
33 | // TODO: add netty customizer
34 | // TODO: add dns resolver
35 | // TODO: add socket address resolver
36 | // TODO: add netty Timer
37 |
38 | return builder.build();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/codec/ByteArrayCodecFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeName;
4 | import io.lettuce.core.codec.ByteArrayCodec;
5 | import io.lettuce.core.codec.RedisCodec;
6 |
7 | @JsonTypeName("byte-array")
8 | public class ByteArrayCodecFactory implements RedisCodecFactory {
9 | @Override
10 | public RedisCodec build() {
11 | return new ByteArrayCodec();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/codec/CompressionCodecFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import io.lettuce.core.codec.CompressionCodec;
6 | import io.lettuce.core.codec.RedisCodec;
7 |
8 | import jakarta.validation.Valid;
9 | import jakarta.validation.constraints.NotNull;
10 |
11 | @JsonTypeName("compression")
12 | public class CompressionCodecFactory implements RedisCodecFactory {
13 | @Valid
14 | @NotNull
15 | @JsonProperty
16 | private RedisCodecFactory delegatee;
17 |
18 | @NotNull
19 | @JsonProperty
20 | private CompressionCodec.CompressionType compressionType;
21 |
22 | public RedisCodecFactory getDelegatee() {
23 | return delegatee;
24 | }
25 |
26 | public void setDelegatee(final RedisCodecFactory delegatee) {
27 | this.delegatee = delegatee;
28 | }
29 |
30 | public CompressionCodec.CompressionType getCompressionType() {
31 | return compressionType;
32 | }
33 |
34 | public void setCompressionType(final CompressionCodec.CompressionType compressionType) {
35 | this.compressionType = compressionType;
36 | }
37 |
38 | @Override
39 | public RedisCodec build() {
40 | return CompressionCodec.valueCompressor(delegatee.build(), compressionType);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/codec/RedisCodecFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 | import io.dropwizard.jackson.Discoverable;
5 | import io.lettuce.core.codec.RedisCodec;
6 |
7 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
8 | public interface RedisCodecFactory extends Discoverable {
9 | RedisCodec build();
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/codec/StringCodecFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeName;
4 | import io.lettuce.core.codec.RedisCodec;
5 | import io.lettuce.core.codec.StringCodec;
6 |
7 | @JsonTypeName("string")
8 | public class StringCodecFactory implements RedisCodecFactory {
9 | @Override
10 | public RedisCodec build() {
11 | return new StringCodec();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/codec/Utf8StringCodecFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeName;
4 | import io.lettuce.core.codec.RedisCodec;
5 | import io.lettuce.core.codec.Utf8StringCodec;
6 |
7 | @JsonTypeName("utf8-string")
8 | public class Utf8StringCodecFactory implements RedisCodecFactory {
9 | @Override
10 | public RedisCodec build() {
11 | return new Utf8StringCodec();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/delay/ConstantDelayFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import io.dropwizard.util.Duration;
6 | import io.lettuce.core.resource.Delay;
7 |
8 | import java.util.function.Supplier;
9 |
10 | import jakarta.validation.constraints.NotNull;
11 |
12 | @JsonTypeName("constant")
13 | public class ConstantDelayFactory implements DelayFactory {
14 | @NotNull
15 | @JsonProperty
16 | private Duration duration;
17 |
18 | public Duration getDuration() {
19 | return duration;
20 | }
21 |
22 | public void setDuration(final Duration duration) {
23 | this.duration = duration;
24 | }
25 |
26 | @Override
27 | public Supplier build() {
28 | final Delay delay = Delay.constant(java.time.Duration.ofMillis(duration.toMilliseconds()));
29 | return () -> delay;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/delay/DecorrelatedJitterDelayFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import io.dropwizard.util.Duration;
6 | import io.lettuce.core.resource.Delay;
7 |
8 | import java.util.concurrent.TimeUnit;
9 | import java.util.function.Supplier;
10 |
11 | import jakarta.validation.constraints.Min;
12 | import jakarta.validation.constraints.NotNull;
13 |
14 | @JsonTypeName("decorrelated-jitter")
15 | public class DecorrelatedJitterDelayFactory implements DelayFactory {
16 | @NotNull
17 | @JsonProperty
18 | private Duration lowerBound = Duration.seconds(0);
19 |
20 | @NotNull
21 | @JsonProperty
22 | private Duration upperBound = Duration.seconds(30);
23 |
24 | @Min(0L)
25 | @JsonProperty
26 | private long base = 0L;
27 |
28 | public Duration getLowerBound() {
29 | return lowerBound;
30 | }
31 |
32 | public void setLowerBound(final Duration lowerBound) {
33 | this.lowerBound = lowerBound;
34 | }
35 |
36 | public Duration getUpperBound() {
37 | return upperBound;
38 | }
39 |
40 | public void setUpperBound(final Duration upperBound) {
41 | this.upperBound = upperBound;
42 | }
43 |
44 | public long getBase() {
45 | return base;
46 | }
47 |
48 | public void setBase(final long base) {
49 | this.base = base;
50 | }
51 |
52 | @Override
53 | public Supplier build() {
54 | return Delay.decorrelatedJitter(lowerBound.toMilliseconds(), upperBound.toMilliseconds(), base, TimeUnit.MILLISECONDS);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/delay/DelayFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 | import io.dropwizard.jackson.Discoverable;
5 | import io.lettuce.core.resource.Delay;
6 |
7 | import java.util.function.Supplier;
8 |
9 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
10 | public interface DelayFactory extends Discoverable {
11 | Supplier build();
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/delay/EqualJitterDelayFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import io.dropwizard.util.Duration;
6 | import io.lettuce.core.resource.Delay;
7 |
8 | import java.util.concurrent.TimeUnit;
9 | import java.util.function.Supplier;
10 |
11 | import jakarta.validation.constraints.Min;
12 | import jakarta.validation.constraints.NotNull;
13 |
14 | @JsonTypeName("equal-jitter")
15 | public class EqualJitterDelayFactory implements DelayFactory {
16 | @NotNull
17 | @JsonProperty
18 | private Duration lowerBound = Duration.seconds(0);
19 |
20 | @NotNull
21 | @JsonProperty
22 | private Duration upperBound = Duration.seconds(30);
23 |
24 | @Min(0L)
25 | @JsonProperty
26 | private long base = 0L;
27 |
28 | public Duration getLowerBound() {
29 | return lowerBound;
30 | }
31 |
32 | public void setLowerBound(final Duration lowerBound) {
33 | this.lowerBound = lowerBound;
34 | }
35 |
36 | public Duration getUpperBound() {
37 | return upperBound;
38 | }
39 |
40 | public void setUpperBound(final Duration upperBound) {
41 | this.upperBound = upperBound;
42 | }
43 |
44 | public long getBase() {
45 | return base;
46 | }
47 |
48 | public void setBase(final long base) {
49 | this.base = base;
50 | }
51 |
52 | @Override
53 | public Supplier build() {
54 | return () -> Delay.equalJitter(lowerBound.toMilliseconds(), upperBound.toMilliseconds(), base, TimeUnit.MILLISECONDS);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/delay/ExponentialDelayFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import io.dropwizard.util.Duration;
6 | import io.lettuce.core.resource.Delay;
7 |
8 | import java.util.concurrent.TimeUnit;
9 | import java.util.function.Supplier;
10 |
11 | import jakarta.validation.constraints.Min;
12 | import jakarta.validation.constraints.NotNull;
13 |
14 | @JsonTypeName("exponential")
15 | public class ExponentialDelayFactory implements DelayFactory {
16 | @NotNull
17 | @JsonProperty
18 | private Duration lowerBound = Duration.seconds(0);
19 |
20 | @NotNull
21 | @JsonProperty
22 | private Duration upperBound = Duration.seconds(30);
23 |
24 | @Min(2)
25 | @JsonProperty
26 | private int powersOf = 2;
27 |
28 | public Duration getLowerBound() {
29 | return lowerBound;
30 | }
31 |
32 | public void setLowerBound(final Duration lowerBound) {
33 | this.lowerBound = lowerBound;
34 | }
35 |
36 | public Duration getUpperBound() {
37 | return upperBound;
38 | }
39 |
40 | public void setUpperBound(final Duration upperBound) {
41 | this.upperBound = upperBound;
42 | }
43 |
44 | public int getPowersOf() {
45 | return powersOf;
46 | }
47 |
48 | public void setPowersOf(final int powersOf) {
49 | this.powersOf = powersOf;
50 | }
51 |
52 | @Override
53 | public Supplier build() {
54 | return () -> Delay.exponential(java.time.Duration.ofMillis(lowerBound.toMilliseconds()),
55 | java.time.Duration.ofMillis(upperBound.toMilliseconds()),
56 | powersOf,
57 | TimeUnit.MILLISECONDS);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/delay/FullJitterDelayFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import io.dropwizard.util.Duration;
6 | import io.lettuce.core.resource.Delay;
7 |
8 | import java.util.concurrent.TimeUnit;
9 | import java.util.function.Supplier;
10 |
11 | import jakarta.validation.constraints.Min;
12 | import jakarta.validation.constraints.NotNull;
13 |
14 | @JsonTypeName("full-jitter")
15 | public class FullJitterDelayFactory implements DelayFactory {
16 | @NotNull
17 | @JsonProperty
18 | private Duration lowerBound = Duration.seconds(0);
19 |
20 | @NotNull
21 | @JsonProperty
22 | private Duration upperBound = Duration.seconds(30);
23 |
24 | @Min(0L)
25 | @JsonProperty
26 | private long base = 0L;
27 |
28 | public Duration getLowerBound() {
29 | return lowerBound;
30 | }
31 |
32 | public void setLowerBound(final Duration lowerBound) {
33 | this.lowerBound = lowerBound;
34 | }
35 |
36 | public Duration getUpperBound() {
37 | return upperBound;
38 | }
39 |
40 | public void setUpperBound(final Duration upperBound) {
41 | this.upperBound = upperBound;
42 | }
43 |
44 | public long getBase() {
45 | return base;
46 | }
47 |
48 | public void setBase(final long base) {
49 | this.base = base;
50 | }
51 |
52 | @Override
53 | public Supplier build() {
54 | return () -> Delay.fullJitter(lowerBound.toMilliseconds(), upperBound.toMilliseconds(), base, TimeUnit.MILLISECONDS);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/event/DefaultEventBusFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.event;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeName;
4 | import io.lettuce.core.event.DefaultEventBus;
5 | import io.lettuce.core.event.EventBus;
6 | import reactor.core.scheduler.Scheduler;
7 |
8 | @JsonTypeName("default")
9 | public class DefaultEventBusFactory implements EventBusFactory {
10 | @Override
11 | public EventBus build(final Scheduler scheduler) {
12 | return new DefaultEventBus(scheduler);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/event/DefaultEventLoopGroupProviderFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.event;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeName;
4 | import io.lettuce.core.resource.DefaultEventLoopGroupProvider;
5 | import io.lettuce.core.resource.EventLoopGroupProvider;
6 |
7 | @JsonTypeName("default")
8 | public class DefaultEventLoopGroupProviderFactory implements EventLoopGroupProviderFactory {
9 | @Override
10 | public EventLoopGroupProvider build(int threads) {
11 | return new DefaultEventLoopGroupProvider(threads);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/event/EventBusFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.event;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 | import io.dropwizard.jackson.Discoverable;
5 | import io.lettuce.core.event.EventBus;
6 | import reactor.core.scheduler.Scheduler;
7 |
8 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
9 | public interface EventBusFactory extends Discoverable {
10 | EventBus build(final Scheduler scheduler);
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/event/EventLoopGroupProviderFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.event;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 | import io.dropwizard.jackson.Discoverable;
5 | import io.lettuce.core.resource.EventLoopGroupProvider;
6 |
7 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
8 | public interface EventLoopGroupProviderFactory extends Discoverable {
9 | EventLoopGroupProvider build(int threads);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/health/Pingable.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.health;
2 |
3 | public interface Pingable {
4 | String ping();
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/health/RedisHealthCheck.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.health;
2 |
3 | import com.codahale.metrics.health.HealthCheck;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | /**
8 | * Performs health checks against a Redis cluster.
9 | * Health check pings the current master, determining whether it is healthy for reads/writes.
10 | */
11 | public class RedisHealthCheck extends HealthCheck {
12 | private static final Logger log = LoggerFactory.getLogger(RedisHealthCheck.class);
13 |
14 | public static final String HEALTHY_STRING = "PONG";
15 |
16 | private final Pingable client;
17 |
18 | public RedisHealthCheck(final Pingable client) {
19 | this.client = client;
20 | }
21 |
22 | public Pingable getClient() {
23 | return client;
24 | }
25 |
26 | @Override
27 | protected Result check() {
28 | try {
29 | return HEALTHY_STRING.equals(client.ping()) ? Result.healthy() : Result.unhealthy("Could not ping Redis");
30 | } catch (final RuntimeException e) {
31 | log.warn("Redis health check failed due to exception", e);
32 | return Result.unhealthy(e);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/managed/RedisClientManager.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.managed;
2 |
3 | import io.dropwizard.lifecycle.Managed;
4 | import io.lettuce.core.AbstractRedisClient;
5 | import io.lettuce.core.api.StatefulConnection;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import static java.util.Objects.requireNonNull;
10 |
11 | /**
12 | * Manages the Redis client lifecycle alongside the application's lifecycle.
13 | */
14 | public class RedisClientManager implements Managed {
15 | private static final Logger log = LoggerFactory.getLogger(RedisClientManager.class);
16 |
17 | private final AbstractRedisClient client;
18 | private final StatefulConnection connection;
19 | private final String name;
20 |
21 | public RedisClientManager(final AbstractRedisClient client, final StatefulConnection connection, final String name) {
22 | this.client = requireNonNull(client);
23 | this.connection = requireNonNull(connection);
24 | this.name = requireNonNull(name);
25 | }
26 |
27 | @Override
28 | public void start() throws Exception {
29 | log.info("redis={} starting", name);
30 | }
31 |
32 | @Override
33 | public void stop() throws Exception {
34 | connection.close();
35 | client.shutdown();
36 | log.info("redis={} shut down", name);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/CommandLatencyRecorderFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
5 | import io.dropwizard.jackson.Discoverable;
6 | import io.lettuce.core.metrics.CommandLatencyRecorder;
7 |
8 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
9 | public interface CommandLatencyRecorderFactory extends Discoverable {
10 | CommandLatencyRecorder build(MetricRegistry metricRegistry);
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/DefaultCommandLatencyCollectorFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.annotation.JsonTypeName;
6 | import io.lettuce.core.metrics.DefaultCommandLatencyCollector;
7 | import io.lettuce.core.metrics.DefaultCommandLatencyCollectorOptions;
8 |
9 | import java.util.concurrent.TimeUnit;
10 |
11 | import jakarta.validation.constraints.NotNull;
12 | import jakarta.validation.constraints.Size;
13 |
14 | @JsonTypeName("default")
15 | public class DefaultCommandLatencyCollectorFactory implements CommandLatencyRecorderFactory {
16 | @NotNull
17 | @JsonProperty
18 | private TimeUnit targetUnit = DefaultCommandLatencyCollectorOptions.DEFAULT_TARGET_UNIT;
19 |
20 | @NotNull
21 | @Size(min = 1)
22 | @JsonProperty
23 | private double[] targetPercentiles = DefaultCommandLatencyCollectorOptions.DEFAULT_TARGET_PERCENTILES;
24 |
25 | @JsonProperty
26 | private boolean resetLatenciesAfterEvent = DefaultCommandLatencyCollectorOptions.DEFAULT_RESET_LATENCIES_AFTER_EVENT;
27 |
28 | @JsonProperty
29 | private boolean localDistinction = DefaultCommandLatencyCollectorOptions.DEFAULT_LOCAL_DISTINCTION;
30 |
31 | @JsonProperty
32 | private boolean enabled = DefaultCommandLatencyCollectorOptions.DEFAULT_ENABLED;
33 |
34 | public TimeUnit getTargetUnit() {
35 | return targetUnit;
36 | }
37 |
38 | public void setTargetUnit(final TimeUnit targetUnit) {
39 | this.targetUnit = targetUnit;
40 | }
41 |
42 | public double[] getTargetPercentiles() {
43 | return targetPercentiles;
44 | }
45 |
46 | public void setTargetPercentiles(final double[] targetPercentiles) {
47 | this.targetPercentiles = targetPercentiles;
48 | }
49 |
50 | public boolean isResetLatenciesAfterEvent() {
51 | return resetLatenciesAfterEvent;
52 | }
53 |
54 | public void setResetLatenciesAfterEvent(final boolean resetLatenciesAfterEvent) {
55 | this.resetLatenciesAfterEvent = resetLatenciesAfterEvent;
56 | }
57 |
58 | public boolean isLocalDistinction() {
59 | return localDistinction;
60 | }
61 |
62 | public void setLocalDistinction(final boolean localDistinction) {
63 | this.localDistinction = localDistinction;
64 | }
65 |
66 | public boolean isEnabled() {
67 | return enabled;
68 | }
69 |
70 | public void setEnabled(final boolean enabled) {
71 | this.enabled = enabled;
72 | }
73 |
74 | @Override
75 | public DefaultCommandLatencyCollector build(MetricRegistry metricRegistry) {
76 | final DefaultCommandLatencyCollectorOptions.Builder builder = DefaultCommandLatencyCollectorOptions.builder()
77 | .targetUnit(targetUnit)
78 | .targetPercentiles(targetPercentiles)
79 | .resetLatenciesAfterEvent(resetLatenciesAfterEvent)
80 | .localDistinction(localDistinction);
81 |
82 | if (enabled) {
83 | builder.enable();
84 | } else {
85 | builder.disable();
86 | }
87 |
88 | return new DefaultCommandLatencyCollector(builder.build());
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/DefaultEventPublisherOptionsFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import io.dropwizard.util.Duration;
6 | import io.lettuce.core.event.DefaultEventPublisherOptions;
7 | import io.lettuce.core.event.EventPublisherOptions;
8 |
9 | import jakarta.validation.constraints.NotNull;
10 |
11 | @JsonTypeName("default")
12 | public class DefaultEventPublisherOptionsFactory implements EventPublisherOptionsFactory {
13 | @NotNull
14 | @JsonProperty
15 | private Duration eventEmitInterval = Duration.minutes(DefaultEventPublisherOptions.DEFAULT_EMIT_INTERVAL);
16 |
17 | public Duration getEventEmitInterval() {
18 | return eventEmitInterval;
19 | }
20 |
21 | public void setEventEmitInterval(final Duration eventEmitInterval) {
22 | this.eventEmitInterval = eventEmitInterval;
23 | }
24 |
25 | @Override
26 | public EventPublisherOptions build() {
27 | return DefaultEventPublisherOptions.builder()
28 | .eventEmitInterval(java.time.Duration.ofSeconds(eventEmitInterval.toSeconds()))
29 | .build();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/DropwizardCommandLatencyRecorder.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.codahale.metrics.Timer;
5 | import io.lettuce.core.metrics.CommandLatencyId;
6 | import io.lettuce.core.metrics.CommandLatencyRecorder;
7 | import java.net.SocketAddress;
8 | import java.util.Map;
9 | import java.util.concurrent.ConcurrentHashMap;
10 | import java.util.concurrent.TimeUnit;
11 | import io.lettuce.core.internal.LettuceAssert;
12 | import io.lettuce.core.protocol.ProtocolKeyword;
13 | import io.netty.channel.local.LocalAddress;
14 |
15 | import static com.codahale.metrics.MetricRegistry.name;
16 |
17 | public class DropwizardCommandLatencyRecorder implements CommandLatencyRecorder {
18 |
19 | static final String METRIC_COMPLETION = "lettuce.command.completion";
20 |
21 | static final String METRIC_FIRST_RESPONSE = "lettuce.command.firstresponse";
22 |
23 | private final MetricRegistry metricRegistry;
24 |
25 | private final boolean isEnabled;
26 |
27 | private final Map completionTimers = new ConcurrentHashMap<>();
28 |
29 | private final Map firstResponseTimers = new ConcurrentHashMap<>();
30 |
31 |
32 | public DropwizardCommandLatencyRecorder(MetricRegistry metricRegistry, boolean isEnabled) {
33 | LettuceAssert.notNull(metricRegistry, "MetricRegistry must not be null");
34 |
35 | this.metricRegistry = metricRegistry;
36 | this.isEnabled = isEnabled;
37 | }
38 |
39 | @Override
40 | public void recordCommandLatency(SocketAddress local, SocketAddress remote, ProtocolKeyword protocolKeyword,
41 | long firstResponseLatency, long completionLatency) {
42 | if (!isEnabled()) {
43 | return;
44 | }
45 |
46 | CommandLatencyId commandLatencyId = CommandLatencyId.create(local, remote, protocolKeyword);
47 |
48 | Timer firstResponseTimer = firstResponseTimers.computeIfAbsent(commandLatencyId, c -> metricRegistry
49 | .timer(name(METRIC_FIRST_RESPONSE, c.commandType().toString())));
50 | firstResponseTimer.update(firstResponseLatency, TimeUnit.NANOSECONDS);
51 |
52 | Timer completionTimer = completionTimers.computeIfAbsent(commandLatencyId, c -> metricRegistry
53 | .timer(name(METRIC_COMPLETION, c.commandType().toString())));
54 | completionTimer.update(completionLatency, TimeUnit.NANOSECONDS);
55 | }
56 |
57 | @Override
58 | public boolean isEnabled() {
59 | return isEnabled;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/DropwizardCommandLatencyRecorderFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.annotation.JsonTypeName;
6 | import io.lettuce.core.metrics.CommandLatencyRecorder;
7 | import io.lettuce.core.metrics.DefaultCommandLatencyCollectorOptions;
8 |
9 | @JsonTypeName("dropwizard")
10 | public class DropwizardCommandLatencyRecorderFactory implements CommandLatencyRecorderFactory {
11 |
12 | @JsonProperty
13 | private boolean enabled = true;
14 |
15 | public boolean isEnabled() {
16 | return enabled;
17 | }
18 |
19 | public void setEnabled(boolean enabled) {
20 | this.enabled = enabled;
21 | }
22 |
23 | @Override
24 | public CommandLatencyRecorder build(MetricRegistry metricRegistry) {
25 | return new DropwizardCommandLatencyRecorder(metricRegistry, enabled);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/EventPublisherOptionsFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 | import io.dropwizard.jackson.Discoverable;
5 | import io.lettuce.core.event.EventPublisherOptions;
6 |
7 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
8 | public interface EventPublisherOptionsFactory extends Discoverable {
9 | EventPublisherOptions build();
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/LettuceMetricsSubscriber.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event;
2 |
3 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
4 | import io.dropwizard.redis.metrics.event.wrapper.EventWrapperFactory;
5 | import io.dropwizard.redis.metrics.event.wrapper.VisitableEventWrapper;
6 | import io.lettuce.core.event.Event;
7 |
8 | import java.util.List;
9 | import java.util.Optional;
10 | import java.util.function.Consumer;
11 |
12 | public class LettuceMetricsSubscriber implements Consumer {
13 | private final List eventVisitors;
14 |
15 | public LettuceMetricsSubscriber(List eventVisitors) {
16 | this.eventVisitors = eventVisitors;
17 | }
18 |
19 | @Override
20 | public void accept(Event event) {
21 | final Optional eventWrapperOpt = EventWrapperFactory.build(event);
22 | eventWrapperOpt.ifPresent(eventWrapper -> eventVisitors.forEach(eventWrapper::accept));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/visitor/ClusterTopologyChangedEventVisitor.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.visitor;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
5 | import io.lettuce.core.event.connection.ConnectedEvent;
6 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
7 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
8 | import io.lettuce.core.event.connection.DisconnectedEvent;
9 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import static java.util.Objects.requireNonNull;
14 |
15 | public class ClusterTopologyChangedEventVisitor implements EventVisitor {
16 | private static final Logger log = LoggerFactory.getLogger(ClusterTopologyChangedEventVisitor.class);
17 |
18 | private final String name;
19 | private final MetricRegistry metrics;
20 |
21 | public ClusterTopologyChangedEventVisitor(final String name, final MetricRegistry metrics) {
22 | this.name = MetricRegistry.name(requireNonNull(name), "event.cluster-topology-change");
23 | this.metrics = requireNonNull(metrics);
24 | }
25 |
26 | @Override
27 | public void visit(final CommandLatencyEvent event) {
28 | // do nothing
29 | }
30 |
31 | @Override
32 | public void visit(final DisconnectedEvent event) {
33 | // do nothing
34 | }
35 |
36 | @Override
37 | public void visit(final ClusterTopologyChangedEvent event) {
38 | metrics.counter(name).inc();
39 | log.debug("Cluster topology change event occurred {}", event);
40 | }
41 |
42 | @Override
43 | public void visit(final ConnectedEvent event) {
44 | // do nothing
45 | }
46 |
47 | @Override
48 | public void visit(final ConnectionActivatedEvent event) {
49 | // do nothing
50 | }
51 |
52 | @Override
53 | public void visit(final ConnectionDeactivatedEvent event) {
54 | // do nothing
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/visitor/CommandLatencyEventVisitor.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.visitor;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
5 | import io.lettuce.core.event.connection.ConnectedEvent;
6 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
7 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
8 | import io.lettuce.core.event.connection.DisconnectedEvent;
9 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
10 |
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | import static java.util.Objects.requireNonNull;
15 |
16 | public class CommandLatencyEventVisitor implements EventVisitor {
17 | private final String name;
18 | private final MetricRegistry metrics;
19 | private final Map metricNames;
20 |
21 | public CommandLatencyEventVisitor(final String name, final MetricRegistry metrics) {
22 | this(name, metrics, new HashMap<>());
23 | }
24 |
25 | // Visible for testing
26 | CommandLatencyEventVisitor(final String name, final MetricRegistry metrics, final Map metricNames) {
27 | this.name = MetricRegistry.name(requireNonNull(name), "event.latency");
28 | this.metrics = requireNonNull(metrics);
29 | this.metricNames = requireNonNull(metricNames);
30 | }
31 |
32 | @Override
33 | public void visit(final CommandLatencyEvent event) {
34 | event.getLatencies().forEach((commandLatencyId, commandMetrics) -> {
35 | final String commandType = commandLatencyId.commandType().toString();
36 | final String metricName = metricNames.computeIfAbsent(commandType, (type) -> MetricRegistry.name(name, type));
37 | metrics.timer(metricName).update(commandMetrics.getCompletion().getMax(), commandMetrics.getTimeUnit());
38 | });
39 | }
40 |
41 | @Override
42 | public void visit(final DisconnectedEvent event) {
43 | // do nothing
44 | }
45 |
46 | @Override
47 | public void visit(final ClusterTopologyChangedEvent event) {
48 | // do nothing
49 | }
50 |
51 | @Override
52 | public void visit(final ConnectedEvent event) {
53 | // do nothing
54 | }
55 |
56 | @Override
57 | public void visit(final ConnectionActivatedEvent event) {
58 | // do nothing
59 | }
60 |
61 | @Override
62 | public void visit(final ConnectionDeactivatedEvent event) {
63 | // do nothing
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/visitor/ConnectedEventVisitor.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.visitor;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
5 | import io.lettuce.core.event.connection.ConnectedEvent;
6 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
7 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
8 | import io.lettuce.core.event.connection.DisconnectedEvent;
9 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import static java.util.Objects.requireNonNull;
14 |
15 | public class ConnectedEventVisitor implements EventVisitor {
16 | private static final Logger log = LoggerFactory.getLogger(ConnectedEventVisitor.class);
17 |
18 | private final String name;
19 | private final MetricRegistry metrics;
20 |
21 | // Visible for testing
22 | public ConnectedEventVisitor(final String name, final MetricRegistry metrics) {
23 | this.name = MetricRegistry.name(requireNonNull(name), "event.connected");
24 | this.metrics = requireNonNull(metrics);
25 | }
26 |
27 | @Override
28 | public void visit(final CommandLatencyEvent event) {
29 | // do nothing
30 | }
31 |
32 | @Override
33 | public void visit(final DisconnectedEvent event) {
34 | // do nothing
35 | }
36 |
37 | @Override
38 | public void visit(final ClusterTopologyChangedEvent event) {
39 | // do nothing
40 | }
41 |
42 | @Override
43 | public void visit(final ConnectedEvent event) {
44 | metrics.counter(name).inc();
45 | log.debug("Connected event occurred: {}", event);
46 | }
47 |
48 | @Override
49 | public void visit(final ConnectionActivatedEvent event) {
50 | // do nothing
51 | }
52 |
53 | @Override
54 | public void visit(final ConnectionDeactivatedEvent event) {
55 | // do nothing
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/visitor/ConnectionActivatedEventVisitor.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.visitor;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
5 | import io.lettuce.core.event.connection.ConnectedEvent;
6 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
7 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
8 | import io.lettuce.core.event.connection.DisconnectedEvent;
9 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import static java.util.Objects.requireNonNull;
14 |
15 | public class ConnectionActivatedEventVisitor implements EventVisitor {
16 | private static final Logger log = LoggerFactory.getLogger(ConnectionActivatedEventVisitor.class);
17 |
18 | private final String name;
19 | private final MetricRegistry metrics;
20 |
21 | // Visible for testing
22 | public ConnectionActivatedEventVisitor(final String name, final MetricRegistry metrics) {
23 | this.name = MetricRegistry.name(requireNonNull(name), "event.connection-activated");
24 | this.metrics = requireNonNull(metrics);
25 | }
26 |
27 | @Override
28 | public void visit(final CommandLatencyEvent event) {
29 | // do nothing
30 | }
31 |
32 | @Override
33 | public void visit(final DisconnectedEvent event) {
34 | // do nothing
35 | }
36 |
37 | @Override
38 | public void visit(final ClusterTopologyChangedEvent event) {
39 | // do nothing
40 | }
41 |
42 | @Override
43 | public void visit(final ConnectedEvent event) {
44 | // do nothing
45 | }
46 |
47 | @Override
48 | public void visit(final ConnectionActivatedEvent event) {
49 | metrics.counter(name).inc();
50 | log.debug("Connection activation event occurred: {}", event);
51 | }
52 |
53 | @Override
54 | public void visit(final ConnectionDeactivatedEvent event) {
55 | // do nothing
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/visitor/ConnectionDeactivatedEventVisitor.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.visitor;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
5 | import io.lettuce.core.event.connection.ConnectedEvent;
6 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
7 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
8 | import io.lettuce.core.event.connection.DisconnectedEvent;
9 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import static java.util.Objects.requireNonNull;
14 |
15 | public class ConnectionDeactivatedEventVisitor implements EventVisitor {
16 | private static final Logger log = LoggerFactory.getLogger(ConnectionDeactivatedEventVisitor.class);
17 |
18 | private final String name;
19 | private final MetricRegistry metrics;
20 |
21 | // Visible for testing
22 | public ConnectionDeactivatedEventVisitor(final String name, final MetricRegistry metrics) {
23 | this.name = MetricRegistry.name(requireNonNull(name), "event.connection-deactivated");
24 | this.metrics = requireNonNull(metrics);
25 | }
26 |
27 | @Override
28 | public void visit(final CommandLatencyEvent event) {
29 | // do nothing
30 | }
31 |
32 | @Override
33 | public void visit(final DisconnectedEvent event) {
34 | // do nothing
35 | }
36 |
37 | @Override
38 | public void visit(final ClusterTopologyChangedEvent event) {
39 | // do nothing
40 | }
41 |
42 | @Override
43 | public void visit(final ConnectedEvent event) {
44 | // do nothing
45 | }
46 |
47 | @Override
48 | public void visit(final ConnectionActivatedEvent event) {
49 | // do nothing
50 | }
51 |
52 | @Override
53 | public void visit(final ConnectionDeactivatedEvent event) {
54 | metrics.counter(name).inc();
55 | log.debug("Connection deactivation event occurred: {}", event);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/visitor/DisconnectedEventVisitor.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.visitor;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
5 | import io.lettuce.core.event.connection.ConnectedEvent;
6 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
7 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
8 | import io.lettuce.core.event.connection.DisconnectedEvent;
9 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import static java.util.Objects.requireNonNull;
14 |
15 | public class DisconnectedEventVisitor implements EventVisitor {
16 | private static final Logger log = LoggerFactory.getLogger(DisconnectedEventVisitor.class);
17 |
18 | private final String name;
19 | private final MetricRegistry metrics;
20 |
21 | // Visible for testing
22 | public DisconnectedEventVisitor(final String name, final MetricRegistry metrics) {
23 | this.name = MetricRegistry.name(requireNonNull(name), "event.disconnected");
24 | this.metrics = requireNonNull(metrics);
25 | }
26 |
27 | @Override
28 | public void visit(final CommandLatencyEvent event) {
29 | // do nothing
30 | }
31 |
32 | @Override
33 | public void visit(final DisconnectedEvent event) {
34 | metrics.counter(name).inc();
35 | log.debug("Disconnected event occurred {}", event);
36 | }
37 |
38 | @Override
39 | public void visit(final ClusterTopologyChangedEvent event) {
40 | // do nothing
41 | }
42 |
43 | @Override
44 | public void visit(final ConnectedEvent event) {
45 | // do nothing
46 | }
47 |
48 | @Override
49 | public void visit(final ConnectionActivatedEvent event) {
50 | // do nothing
51 | }
52 |
53 | @Override
54 | public void visit(final ConnectionDeactivatedEvent event) {
55 | // do nothing
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/visitor/EventVisitor.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.visitor;
2 |
3 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
4 | import io.lettuce.core.event.connection.ConnectedEvent;
5 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
6 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
7 | import io.lettuce.core.event.connection.DisconnectedEvent;
8 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
9 |
10 | public interface EventVisitor {
11 | void visit(CommandLatencyEvent event);
12 |
13 | void visit(DisconnectedEvent event);
14 |
15 | void visit(ClusterTopologyChangedEvent event);
16 |
17 | void visit(ConnectedEvent event);
18 |
19 | void visit(ConnectionActivatedEvent event);
20 |
21 | void visit(ConnectionDeactivatedEvent event);
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/wrapper/EventWrapperFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.wrapper;
2 |
3 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
4 | import io.lettuce.core.event.Event;
5 | import io.lettuce.core.event.connection.ConnectedEvent;
6 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
7 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
8 | import io.lettuce.core.event.connection.DisconnectedEvent;
9 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
10 |
11 | import java.util.Optional;
12 |
13 | public class EventWrapperFactory {
14 | public static VisitableEventWrapper build(final CommandLatencyEvent event) {
15 | return new VisitableCommandLatencyEventWrapper(event);
16 | }
17 |
18 | public static VisitableEventWrapper build(final ClusterTopologyChangedEvent event) {
19 | return new VisitableClusterTopologyEventWrapper(event);
20 | }
21 |
22 | public static VisitableEventWrapper build(final ConnectedEvent event) {
23 | return new VisitableConnectedEventWrapper(event);
24 | }
25 |
26 | public static VisitableEventWrapper build(final ConnectionActivatedEvent event) {
27 | return new VisitableConnectionActivatedEventWrapper(event);
28 | }
29 |
30 | public static VisitableEventWrapper build(final ConnectionDeactivatedEvent event) {
31 | return new VisitableConnectionDeactivatedEventWrapper(event);
32 | }
33 |
34 | public static VisitableEventWrapper build(final DisconnectedEvent event) {
35 | return new VisitableDisconnectedEventWrapper(event);
36 | }
37 |
38 | public static Optional build(final Event event) {
39 | // TODO: any way to avoid needing to do these instanceof checks?
40 | if (event instanceof CommandLatencyEvent) {
41 | return Optional.of(build((CommandLatencyEvent) event));
42 | } else if (event instanceof ClusterTopologyChangedEvent) {
43 | return Optional.of(build((ClusterTopologyChangedEvent) event));
44 | } else if (event instanceof ConnectedEvent) {
45 | return Optional.of(build((ConnectedEvent) event));
46 | } else if (event instanceof ConnectionActivatedEvent) {
47 | return Optional.of(build((ConnectionActivatedEvent) event));
48 | } else if (event instanceof ConnectionDeactivatedEvent) {
49 | return Optional.of(build((ConnectionDeactivatedEvent) event));
50 | } else if (event instanceof DisconnectedEvent) {
51 | return Optional.of(build((DisconnectedEvent) event));
52 | }
53 |
54 | return Optional.empty();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/wrapper/VisitableClusterTopologyEventWrapper.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.wrapper;
2 |
3 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
4 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
5 |
6 | import static java.util.Objects.requireNonNull;
7 |
8 | public class VisitableClusterTopologyEventWrapper implements VisitableEventWrapper {
9 | private final ClusterTopologyChangedEvent event;
10 |
11 | public VisitableClusterTopologyEventWrapper(final ClusterTopologyChangedEvent event) {
12 | this.event = requireNonNull(event);
13 | }
14 |
15 | @Override
16 | public void accept(final EventVisitor visitor) {
17 | visitor.visit(event);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/wrapper/VisitableCommandLatencyEventWrapper.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.wrapper;
2 |
3 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
4 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
5 |
6 | import static java.util.Objects.requireNonNull;
7 |
8 | public class VisitableCommandLatencyEventWrapper implements VisitableEventWrapper {
9 | private final CommandLatencyEvent event;
10 |
11 | public VisitableCommandLatencyEventWrapper(final CommandLatencyEvent event) {
12 | this.event = requireNonNull(event);
13 | }
14 |
15 | @Override
16 | public void accept(final EventVisitor visitor) {
17 | visitor.visit(event);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/wrapper/VisitableConnectedEventWrapper.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.wrapper;
2 |
3 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
4 | import io.lettuce.core.event.connection.ConnectedEvent;
5 |
6 | import static java.util.Objects.requireNonNull;
7 |
8 | public class VisitableConnectedEventWrapper implements VisitableEventWrapper {
9 | private final ConnectedEvent event;
10 |
11 | public VisitableConnectedEventWrapper(final ConnectedEvent event) {
12 | this.event = requireNonNull(event);
13 | }
14 |
15 | @Override
16 | public void accept(final EventVisitor visitor) {
17 | visitor.visit(event);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/wrapper/VisitableConnectionActivatedEventWrapper.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.wrapper;
2 |
3 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
4 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
5 |
6 | import static java.util.Objects.requireNonNull;
7 |
8 | public class VisitableConnectionActivatedEventWrapper implements VisitableEventWrapper {
9 | private final ConnectionActivatedEvent event;
10 |
11 | public VisitableConnectionActivatedEventWrapper(final ConnectionActivatedEvent event) {
12 | this.event = requireNonNull(event);
13 | }
14 |
15 | @Override
16 | public void accept(final EventVisitor visitor) {
17 | visitor.visit(event);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/wrapper/VisitableConnectionDeactivatedEventWrapper.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.wrapper;
2 |
3 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
4 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
5 |
6 | import static java.util.Objects.requireNonNull;
7 |
8 | public class VisitableConnectionDeactivatedEventWrapper implements VisitableEventWrapper {
9 | private final ConnectionDeactivatedEvent event;
10 |
11 | public VisitableConnectionDeactivatedEventWrapper(final ConnectionDeactivatedEvent event) {
12 | this.event = requireNonNull(event);
13 | }
14 |
15 | @Override
16 | public void accept(final EventVisitor visitor) {
17 | visitor.visit(event);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/wrapper/VisitableDisconnectedEventWrapper.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.wrapper;
2 |
3 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
4 | import io.lettuce.core.event.connection.DisconnectedEvent;
5 |
6 | import static java.util.Objects.requireNonNull;
7 |
8 | public class VisitableDisconnectedEventWrapper implements VisitableEventWrapper {
9 | private final DisconnectedEvent event;
10 |
11 | public VisitableDisconnectedEventWrapper(final DisconnectedEvent event) {
12 | this.event = requireNonNull(event);
13 | }
14 |
15 | @Override
16 | public void accept(final EventVisitor visitor) {
17 | visitor.visit(event);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/metrics/event/wrapper/VisitableEventWrapper.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event.wrapper;
2 |
3 | import io.dropwizard.redis.metrics.event.visitor.EventVisitor;
4 |
5 | public interface VisitableEventWrapper {
6 | void accept(EventVisitor visitor);
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/netty/DefaultEventExecutorGroupFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.netty;
2 |
3 | import com.codahale.metrics.InstrumentedThreadFactory;
4 | import com.codahale.metrics.MetricRegistry;
5 | import com.fasterxml.jackson.annotation.JsonTypeName;
6 | import io.netty.util.concurrent.DefaultEventExecutorGroup;
7 | import io.netty.util.concurrent.DefaultThreadFactory;
8 | import io.netty.util.concurrent.EventExecutorGroup;
9 |
10 | import java.util.concurrent.ThreadFactory;
11 |
12 | @JsonTypeName("default")
13 | public class DefaultEventExecutorGroupFactory implements EventExecutorGroupFactory {
14 | @Override
15 | public EventExecutorGroup build(final int threadPoolSize, final String name, final MetricRegistry metrics) {
16 | String poolName = String.format("%s-eventExecutorLoop", name);
17 | final ThreadFactory threadFactory = new DefaultThreadFactory(poolName, true);
18 | return new DefaultEventExecutorGroup(threadPoolSize, new InstrumentedThreadFactory(threadFactory, metrics, poolName));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/netty/EventExecutorGroupFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.netty;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
5 | import io.netty.util.concurrent.EventExecutorGroup;
6 |
7 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
8 | public interface EventExecutorGroupFactory {
9 | EventExecutorGroup build(final int threadPoolSize, final String name, final MetricRegistry metrics);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/socket/SocketOptionsFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.socket;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import io.dropwizard.util.Duration;
5 | import io.lettuce.core.SocketOptions;
6 |
7 | import jakarta.validation.constraints.NotNull;
8 |
9 | public class SocketOptionsFactory {
10 | @NotNull
11 | @JsonProperty
12 | private Duration connectTimeout = Duration.seconds(SocketOptions.DEFAULT_CONNECT_TIMEOUT);
13 |
14 | @JsonProperty
15 | private boolean keepAlive = SocketOptions.DEFAULT_SO_KEEPALIVE;
16 |
17 | @JsonProperty
18 | private boolean tcpNoDelay = SocketOptions.DEFAULT_SO_NO_DELAY;
19 |
20 | public Duration getConnectTimeout() {
21 | return connectTimeout;
22 | }
23 |
24 | public void setConnectTimeout(final Duration connectTimeout) {
25 | this.connectTimeout = connectTimeout;
26 | }
27 |
28 | public boolean isKeepAlive() {
29 | return keepAlive;
30 | }
31 |
32 | public void setKeepAlive(final boolean keepAlive) {
33 | this.keepAlive = keepAlive;
34 | }
35 |
36 | public boolean isTcpNoDelay() {
37 | return tcpNoDelay;
38 | }
39 |
40 | public void setTcpNoDelay(final boolean tcpNoDelay) {
41 | this.tcpNoDelay = tcpNoDelay;
42 | }
43 |
44 | public SocketOptions build() {
45 | return SocketOptions.builder()
46 | .connectTimeout(java.time.Duration.ofSeconds(connectTimeout.toSeconds()))
47 | .keepAlive(keepAlive)
48 | .tcpNoDelay(tcpNoDelay)
49 | .build();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/ssl/SslOptionsFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.ssl;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import io.lettuce.core.SslOptions;
5 | import io.netty.handler.ssl.SslProvider;
6 |
7 | import java.io.File;
8 |
9 | import jakarta.validation.constraints.NotNull;
10 |
11 | public class SslOptionsFactory {
12 | @JsonProperty
13 | private boolean enabled = true;
14 |
15 | @NotNull
16 | @JsonProperty
17 | private SslProvider sslProvider = SslOptions.DEFAULT_SSL_PROVIDER;
18 |
19 | @NotNull
20 | @JsonProperty
21 | private File keystore;
22 |
23 | @JsonProperty
24 | private String keystorePassword;
25 |
26 | @NotNull
27 | @JsonProperty
28 | private File truststore;
29 |
30 | @JsonProperty
31 | private String truststorePassword;
32 |
33 | public boolean isEnabled() {
34 | return enabled;
35 | }
36 |
37 | public void setEnabled(final boolean enabled) {
38 | this.enabled = enabled;
39 | }
40 |
41 | public SslProvider getSslProvider() {
42 | return sslProvider;
43 | }
44 |
45 | public void setSslProvider(final SslProvider sslProvider) {
46 | this.sslProvider = sslProvider;
47 | }
48 |
49 | public File getKeystore() {
50 | return keystore;
51 | }
52 |
53 | public void setKeystore(final File keystore) {
54 | this.keystore = keystore;
55 | }
56 |
57 | public String getKeystorePassword() {
58 | return keystorePassword;
59 | }
60 |
61 | public void setKeystorePassword(final String keystorePassword) {
62 | this.keystorePassword = keystorePassword;
63 | }
64 |
65 | public File getTruststore() {
66 | return truststore;
67 | }
68 |
69 | public void setTruststore(final File truststore) {
70 | this.truststore = truststore;
71 | }
72 |
73 | public String getTruststorePassword() {
74 | return truststorePassword;
75 | }
76 |
77 | public void setTruststorePassword(final String truststorePassword) {
78 | this.truststorePassword = truststorePassword;
79 | }
80 |
81 | public SslOptions build() {
82 | final SslOptions.Builder builder = SslOptions.builder();
83 |
84 | switch (sslProvider) {
85 | case JDK:
86 | builder.jdkSslProvider();
87 | break;
88 | case OPENSSL:
89 | case OPENSSL_REFCNT:
90 | builder.openSslProvider();
91 | break;
92 | }
93 |
94 | if (keystorePassword != null) {
95 | builder.keystore(keystore, keystorePassword.toCharArray());
96 | } else {
97 | builder.keystore(keystore);
98 | }
99 |
100 | if (truststorePassword != null) {
101 | builder.truststore(truststore, truststorePassword);
102 | } else {
103 | builder.truststore(truststore);
104 | }
105 |
106 | return builder.build();
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/timeout/TimeoutOptionsFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.timeout;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import io.dropwizard.util.Duration;
5 | import io.lettuce.core.TimeoutOptions;
6 |
7 | public class TimeoutOptionsFactory {
8 | @JsonProperty
9 | private boolean timeoutCommands = TimeoutOptions.DEFAULT_TIMEOUT_COMMANDS;
10 |
11 | @JsonProperty
12 | private boolean applyConnectionTimeout = false;
13 |
14 | @JsonProperty
15 | private Duration fixedTimeout;
16 |
17 | public boolean isTimeoutCommands() {
18 | return timeoutCommands;
19 | }
20 |
21 | public void setTimeoutCommands(final boolean timeoutCommands) {
22 | this.timeoutCommands = timeoutCommands;
23 | }
24 |
25 | public boolean isApplyConnectionTimeout() {
26 | return applyConnectionTimeout;
27 | }
28 |
29 | public void setApplyConnectionTimeout(final boolean applyConnectionTimeout) {
30 | this.applyConnectionTimeout = applyConnectionTimeout;
31 | }
32 |
33 | public Duration getFixedTimeout() {
34 | return fixedTimeout;
35 | }
36 |
37 | public void setFixedTimeout(final Duration fixedTimeout) {
38 | this.fixedTimeout = fixedTimeout;
39 | }
40 |
41 | public TimeoutOptions build() {
42 | final TimeoutOptions.Builder builder = TimeoutOptions.builder()
43 | .timeoutCommands(timeoutCommands);
44 |
45 | if (applyConnectionTimeout) {
46 | builder.connectionTimeout();
47 | }
48 |
49 | if (fixedTimeout != null) {
50 | builder.fixedTimeout(java.time.Duration.ofMillis(fixedTimeout.toMilliseconds()));
51 | }
52 |
53 | return builder.build();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/topology/ClusterTopologyRefreshOptionsFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.topology;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import io.dropwizard.util.Duration;
5 | import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
6 |
7 | import java.util.Set;
8 |
9 | import jakarta.validation.constraints.Min;
10 | import jakarta.validation.constraints.NotNull;
11 |
12 | public class ClusterTopologyRefreshOptionsFactory {
13 | @JsonProperty
14 | private boolean periodicRefreshEnabled = ClusterTopologyRefreshOptions.DEFAULT_PERIODIC_REFRESH_ENABLED;
15 |
16 | @NotNull
17 | @JsonProperty
18 | private Duration refreshPeriod = Duration.seconds(ClusterTopologyRefreshOptions.DEFAULT_REFRESH_PERIOD);
19 |
20 | @JsonProperty
21 | private boolean closeStaleConnections = ClusterTopologyRefreshOptions.DEFAULT_CLOSE_STALE_CONNECTIONS;
22 |
23 | @JsonProperty
24 | private boolean dynamicRefreshSources = ClusterTopologyRefreshOptions.DEFAULT_DYNAMIC_REFRESH_SOURCES;
25 |
26 | @NotNull
27 | @JsonProperty
28 | private Set adaptiveRefreshTriggers =
29 | ClusterTopologyRefreshOptions.DEFAULT_ADAPTIVE_REFRESH_TRIGGERS;
30 |
31 | @Min(0)
32 | @JsonProperty
33 | private int refreshTriggersReconnectAttempts = ClusterTopologyRefreshOptions.DEFAULT_REFRESH_TRIGGERS_RECONNECT_ATTEMPTS;
34 |
35 | public boolean isPeriodicRefreshEnabled() {
36 | return periodicRefreshEnabled;
37 | }
38 |
39 | public void setPeriodicRefreshEnabled(final boolean periodicRefreshEnabled) {
40 | this.periodicRefreshEnabled = periodicRefreshEnabled;
41 | }
42 |
43 | public Duration getRefreshPeriod() {
44 | return refreshPeriod;
45 | }
46 |
47 | public void setRefreshPeriod(final Duration refreshPeriod) {
48 | this.refreshPeriod = refreshPeriod;
49 | }
50 |
51 | public boolean isCloseStaleConnections() {
52 | return closeStaleConnections;
53 | }
54 |
55 | public void setCloseStaleConnections(final boolean closeStaleConnections) {
56 | this.closeStaleConnections = closeStaleConnections;
57 | }
58 |
59 | public boolean isDynamicRefreshSources() {
60 | return dynamicRefreshSources;
61 | }
62 |
63 | public void setDynamicRefreshSources(final boolean dynamicRefreshSources) {
64 | this.dynamicRefreshSources = dynamicRefreshSources;
65 | }
66 |
67 | public Set getAdaptiveRefreshTriggers() {
68 | return adaptiveRefreshTriggers;
69 | }
70 |
71 | public void setAdaptiveRefreshTriggers(final Set adaptiveRefreshTriggers) {
72 | this.adaptiveRefreshTriggers = adaptiveRefreshTriggers;
73 | }
74 |
75 | public int getRefreshTriggersReconnectAttempts() {
76 | return refreshTriggersReconnectAttempts;
77 | }
78 |
79 | public void setRefreshTriggersReconnectAttempts(final int refreshTriggersReconnectAttempts) {
80 | this.refreshTriggersReconnectAttempts = refreshTriggersReconnectAttempts;
81 | }
82 |
83 | public ClusterTopologyRefreshOptions build() {
84 | return ClusterTopologyRefreshOptions.builder()
85 | .enablePeriodicRefresh(periodicRefreshEnabled)
86 | .refreshPeriod(java.time.Duration.ofSeconds(refreshPeriod.toSeconds()))
87 | .closeStaleConnections(closeStaleConnections)
88 | .dynamicRefreshSources(dynamicRefreshSources)
89 | .enableAdaptiveRefreshTrigger(adaptiveRefreshTriggers.toArray(new ClusterTopologyRefreshOptions.RefreshTrigger[0]))
90 | .build();
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/uri/RedisModeURIFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.uri;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import com.google.common.net.HostAndPort;
6 | import io.lettuce.core.RedisURI;
7 |
8 | import jakarta.validation.Valid;
9 | import jakarta.validation.constraints.NotNull;
10 |
11 | @JsonTypeName("redis")
12 | public class RedisModeURIFactory extends RedisURIFactory {
13 | @Valid
14 | @NotNull
15 | @JsonProperty
16 | private HostAndPort node;
17 |
18 | @JsonProperty
19 | private boolean ssl = false;
20 |
21 | @JsonProperty
22 | private boolean startTls = false;
23 |
24 | @JsonProperty
25 | private boolean verifyPeer = true;
26 |
27 | public HostAndPort getNode() {
28 | return node;
29 | }
30 |
31 | public void setNode(final HostAndPort node) {
32 | this.node = node;
33 | }
34 |
35 | public boolean isSsl() {
36 | return ssl;
37 | }
38 |
39 | public void setSsl(final boolean ssl) {
40 | this.ssl = ssl;
41 | }
42 |
43 | public boolean isStartTls() {
44 | return startTls;
45 | }
46 |
47 | public void setStartTls(final boolean startTls) {
48 | this.startTls = startTls;
49 | }
50 |
51 | public boolean isVerifyPeer() {
52 | return verifyPeer;
53 | }
54 |
55 | public void setVerifyPeer(final boolean verifyPeer) {
56 | this.verifyPeer = verifyPeer;
57 | }
58 |
59 | @Override
60 | public RedisURI build() {
61 | final RedisURI.Builder builder = RedisURI.builder()
62 | .withHost(node.getHost())
63 | .withPort(node.getPort())
64 | .withSsl(ssl)
65 | .withStartTls(startTls)
66 | .withVerifyPeer(verifyPeer)
67 | .withTimeout(java.time.Duration.ofSeconds(timeout.toSeconds()));
68 |
69 | if (clientName != null) {
70 | builder.withClientName(clientName);
71 | }
72 |
73 | if (username != null && password != null) {
74 | builder.withAuthentication(username, password);
75 | } else if (password != null) {
76 | builder.withPassword(password);
77 | }
78 |
79 | return builder.build();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/uri/RedisURIFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.uri;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
5 | import io.dropwizard.jackson.Discoverable;
6 | import io.dropwizard.util.Duration;
7 | import io.lettuce.core.RedisURI;
8 |
9 | import jakarta.validation.constraints.NotNull;
10 |
11 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
12 | public abstract class RedisURIFactory implements Discoverable {
13 | @NotNull
14 | @JsonProperty
15 | protected Duration timeout = Duration.seconds(RedisURI.DEFAULT_TIMEOUT);
16 |
17 | @JsonProperty
18 | protected String clientName;
19 |
20 | @JsonProperty
21 | protected String username;
22 |
23 | @JsonProperty
24 | protected String password;
25 |
26 | public Duration getTimeout() {
27 | return timeout;
28 | }
29 |
30 | public void setTimeout(final Duration timeout) {
31 | this.timeout = timeout;
32 | }
33 |
34 | public String getClientName() {
35 | return clientName;
36 | }
37 |
38 | public void setClientName(final String clientName) {
39 | this.clientName = clientName;
40 | }
41 |
42 | public String getUsername() {
43 | return username;
44 | }
45 |
46 | public void setUsername(String username) {
47 | this.username = username;
48 | }
49 |
50 | public String getPassword() {
51 | return password;
52 | }
53 |
54 | public void setPassword(final String password) {
55 | this.password = password;
56 | }
57 |
58 | public abstract RedisURI build();
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/io/dropwizard/redis/uri/SentinelModeURIFactory.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.uri;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonTypeName;
5 | import com.google.common.net.HostAndPort;
6 | import io.lettuce.core.RedisURI;
7 | import org.hibernate.validator.constraints.NotEmpty;
8 |
9 | import jakarta.validation.Valid;
10 | import java.util.Collections;
11 | import java.util.Set;
12 |
13 | @JsonTypeName("sentinel")
14 | public class SentinelModeURIFactory extends RedisURIFactory {
15 | @Valid
16 | @NotEmpty
17 | @JsonProperty
18 | private Set sentinels = Collections.emptySet();
19 |
20 | @JsonProperty
21 | private String sentinelMasterId;
22 |
23 | public Set getSentinels() {
24 | return sentinels;
25 | }
26 |
27 | public void setSentinels(final Set sentinels) {
28 | this.sentinels = sentinels;
29 | }
30 |
31 | public String getSentinelMasterId() {
32 | return sentinelMasterId;
33 | }
34 |
35 | public void setSentinelMasterId(final String sentinelMasterId) {
36 | this.sentinelMasterId = sentinelMasterId;
37 | }
38 |
39 | @Override
40 | public RedisURI build() {
41 | final RedisURI.Builder builder = RedisURI.builder()
42 | .withTimeout(java.time.Duration.ofSeconds(timeout.toSeconds()));
43 |
44 | sentinels.forEach(sentinel -> builder.withSentinel(sentinel.getHost(), sentinel.getPort()));
45 |
46 | if (clientName != null) {
47 | builder.withClientName(clientName);
48 | }
49 |
50 | if (username != null && password != null) {
51 | builder.withAuthentication(username, password);
52 | } else if (password != null) {
53 | builder.withPassword(password);
54 | }
55 |
56 | if (sentinelMasterId != null) {
57 | builder.withSentinelMasterId(sentinelMasterId);
58 | }
59 |
60 | return builder.build();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.jackson.Discoverable:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.AbstractRedisClientFactory
2 | io.dropwizard.redis.clientresources.ClientResourcesFactory
3 | io.dropwizard.redis.codec.RedisCodecFactory
4 | io.dropwizard.redis.delay.DelayFactory
5 | io.dropwizard.redis.event.EventBusFactory
6 | io.dropwizard.redis.event.EventLoopGroupProviderFactory
7 | io.dropwizard.redis.metrics.CommandLatencyRecorderFactory
8 | io.dropwizard.redis.metrics.EventPublisherOptionsFactory
9 | io.dropwizard.redis.netty.EventExecutorGroupFactory
10 | io.dropwizard.redis.uri.RedisURIFactory
11 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.AbstractRedisClientFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.RedisClientFactory
2 | io.dropwizard.redis.RedisClusterClientFactory
3 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.clientresources.ClientResourcesFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.clientresources.DefaultClientResourcesFactory
2 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.codec.RedisCodecFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.codec.ByteArrayCodecFactory
2 | io.dropwizard.redis.codec.CompressionCodecFactory
3 | io.dropwizard.redis.codec.StringCodecFactory
4 | io.dropwizard.redis.codec.Utf8StringCodecFactory
5 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.delay.DelayFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.delay.ConstantDelayFactory
2 | io.dropwizard.redis.delay.DecorrelatedJitterDelayFactory
3 | io.dropwizard.redis.delay.EqualJitterDelayFactory
4 | io.dropwizard.redis.delay.ExponentialDelayFactory
5 | io.dropwizard.redis.delay.FullJitterDelayFactory
6 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.event.EventBusFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.event.DefaultEventBusFactory
2 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.event.EventLoopGroupProviderFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.event.DefaultEventLoopGroupProviderFactory
2 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.metrics.CommandLatencyRecorderFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.metrics.DefaultCommandLatencyCollectorFactory
2 | io.dropwizard.redis.metrics.DropwizardCommandLatencyRecorderFactory
3 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.metrics.EventPublisherOptionsFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.metrics.DefaultEventPublisherOptionsFactory
2 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.netty.EventExecutorGroupFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.netty.DefaultEventExecutorGroupFactory
2 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/io.dropwizard.redis.uri.RedisURIFactory:
--------------------------------------------------------------------------------
1 | io.dropwizard.redis.uri.RedisModeURIFactory
2 | io.dropwizard.redis.uri.SentinelModeURIFactory
3 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/clientoptions/ClusterClientOptionsFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.clientoptions;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import io.dropwizard.configuration.YamlConfigurationFactory;
5 | import io.dropwizard.jackson.Jackson;
6 | import io.dropwizard.jersey.validation.Validators;
7 | import io.lettuce.core.ClientOptions;
8 | import io.lettuce.core.cluster.ClusterClientOptions;
9 | import org.junit.jupiter.api.Test;
10 |
11 | import jakarta.validation.Validator;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 |
15 | public class ClusterClientOptionsFactoryTest {
16 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
17 | private final Validator validator = Validators.newValidator();
18 | private final YamlConfigurationFactory configFactory =
19 | new YamlConfigurationFactory<>(ClusterClientOptionsFactory.class, validator, objectMapper, "dw");
20 |
21 | @Test
22 | public void shouldBuildClusterClientOptions() throws Exception {
23 | final ClusterClientOptionsFactory factory = configFactory.build();
24 |
25 | assertThat(factory.getSslOptions())
26 | .isNull();
27 | assertThat(factory.getMaxRedirects())
28 | .isEqualTo(ClusterClientOptions.DEFAULT_MAX_REDIRECTS);
29 | assertThat(factory.getTopologyRefreshOptions())
30 | .isNull();
31 | assertThat(factory.isAutoReconnect())
32 | .isEqualTo(ClusterClientOptions.DEFAULT_AUTO_RECONNECT);
33 | assertThat(factory.isValidateClusterNodeMembership())
34 | .isEqualTo(ClusterClientOptions.DEFAULT_VALIDATE_CLUSTER_MEMBERSHIP);
35 | assertThat(factory.isCancelCommandsOnReconnectFailure())
36 | .isEqualTo(ClusterClientOptions.DEFAULT_CANCEL_CMD_RECONNECT_FAIL);
37 | assertThat(factory.isPingBeforeActivateConnection())
38 | .isEqualTo(ClusterClientOptions.DEFAULT_PING_BEFORE_ACTIVATE_CONNECTION);
39 | assertThat(factory.isPublishOnScheduler())
40 | .isEqualTo(ClusterClientOptions.DEFAULT_PUBLISH_ON_SCHEDULER);
41 | assertThat(factory.isSuspendReconnectOnProtocolFailure())
42 | .isEqualTo(ClusterClientOptions.DEFAULT_SUSPEND_RECONNECT_PROTO_FAIL);
43 | assertThat(factory.getDisconnectedBehavior())
44 | .isEqualTo(ClientOptions.DEFAULT_DISCONNECTED_BEHAVIOR);
45 | assertThat(factory.getRequestQueueSize())
46 | .isEqualTo(ClusterClientOptions.DEFAULT_REQUEST_QUEUE_SIZE);
47 | assertThat(factory.getSocketOptions())
48 | .isNotNull();
49 | assertThat(factory.getTimeoutOptions())
50 | .isNotNull();
51 |
52 | assertThat(factory.build()).isNotNull();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/clientresources/DefaultClientResourcesFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.clientresources;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.google.common.io.Resources;
6 | import io.dropwizard.configuration.YamlConfigurationFactory;
7 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
8 | import io.dropwizard.jackson.Jackson;
9 | import io.dropwizard.jersey.validation.Validators;
10 | import io.dropwizard.redis.delay.ExponentialDelayFactory;
11 | import io.lettuce.core.resource.ClientResources;
12 | import io.lettuce.core.resource.DefaultClientResources;
13 | import org.junit.jupiter.api.Test;
14 |
15 | import java.io.File;
16 |
17 | import jakarta.validation.Validator;
18 |
19 | import static org.assertj.core.api.Assertions.assertThat;
20 |
21 | public class DefaultClientResourcesFactoryTest {
22 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
23 | private final Validator validator = Validators.newValidator();
24 | private final YamlConfigurationFactory configFactory =
25 | new YamlConfigurationFactory<>(ClientResourcesFactory.class, validator, objectMapper, "dw");
26 |
27 | @Test
28 | public void shouldBuildClientResources() throws Exception {
29 | final File yml = new File(Resources.getResource("yaml/clientresources/default.yaml").toURI());
30 | final ClientResourcesFactory factory = configFactory.build(yml);
31 | assertThat(factory)
32 | .isInstanceOf(DefaultClientResourcesFactory.class);
33 |
34 | final DefaultClientResourcesFactory defaultClientResourcesFactory = (DefaultClientResourcesFactory) factory;
35 | assertThat(defaultClientResourcesFactory.getCommandLatencyRecorder())
36 | .isNotNull();
37 | assertThat(defaultClientResourcesFactory.getEventPublisherOptions())
38 | .isNotNull();
39 | assertThat(defaultClientResourcesFactory.getEventBusFactory())
40 | .isNotNull();
41 | assertThat(defaultClientResourcesFactory.getEventExecutorGroup())
42 | .isNotNull();
43 | assertThat(defaultClientResourcesFactory.getEventLoopGroupProvider())
44 | .isNotNull();
45 | assertThat(defaultClientResourcesFactory.getComputationThreads())
46 | .isEqualTo(DefaultClientResources.DEFAULT_COMPUTATION_THREADS);
47 | assertThat(defaultClientResourcesFactory.getIoThreads())
48 | .isEqualTo(DefaultClientResources.DEFAULT_IO_THREADS);
49 | assertThat(defaultClientResourcesFactory.getDelay())
50 | .isInstanceOf(ExponentialDelayFactory.class);
51 |
52 | assertThat(defaultClientResourcesFactory.build("name", new MetricRegistry(), null))
53 | .isInstanceOf(ClientResources.class);
54 | }
55 |
56 | @Test
57 | public void isDiscoverable() {
58 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
59 | .contains(DefaultClientResourcesFactory.class);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/codec/ByteArrayCodecFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.assertj.core.api.Assertions.assertThat;
7 |
8 | public class ByteArrayCodecFactoryTest {
9 | @Test
10 | public void isDiscoverable() {
11 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
12 | .contains(ByteArrayCodecFactory.class);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/codec/CompressionCodecFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
7 | import io.dropwizard.jackson.Jackson;
8 | import io.dropwizard.jersey.validation.Validators;
9 | import io.lettuce.core.codec.CompressionCodec;
10 | import io.lettuce.core.codec.RedisCodec;
11 | import org.junit.jupiter.api.Test;
12 |
13 | import java.io.File;
14 |
15 | import jakarta.validation.Validator;
16 |
17 | import static org.assertj.core.api.Assertions.assertThat;
18 |
19 | public class CompressionCodecFactoryTest {
20 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
21 | private final Validator validator = Validators.newValidator();
22 | private final YamlConfigurationFactory configFactory =
23 | new YamlConfigurationFactory<>(RedisCodecFactory.class, validator, objectMapper, "dw");
24 |
25 | @Test
26 | public void shouldBuildACompressionCodec() throws Exception {
27 | final File yml = new File(Resources.getResource("yaml/codec/compression.yaml").toURI());
28 | final RedisCodecFactory factory = configFactory.build(yml);
29 | assertThat(factory)
30 | .isInstanceOf(CompressionCodecFactory.class);
31 |
32 | final CompressionCodecFactory compressionCodecFactory = (CompressionCodecFactory) factory;
33 | assertThat(compressionCodecFactory.getCompressionType())
34 | .isEqualTo(CompressionCodec.CompressionType.GZIP);
35 | assertThat(compressionCodecFactory.getDelegatee())
36 | .isInstanceOf(StringCodecFactory.class);
37 | assertThat(compressionCodecFactory.build())
38 | .isInstanceOf(RedisCodec.class);
39 | }
40 |
41 | @Test
42 | public void isDiscoverable() {
43 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
44 | .contains(CompressionCodecFactory.class);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/codec/StringCodecFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.assertj.core.api.Assertions.assertThat;
7 |
8 | public class StringCodecFactoryTest {
9 | @Test
10 | public void isDiscoverable() {
11 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
12 | .contains(StringCodecFactory.class);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/codec/Utf8StringCodecFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.codec;
2 |
3 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.assertj.core.api.Assertions.assertThat;
7 |
8 | public class Utf8StringCodecFactoryTest {
9 | @Test
10 | public void isDiscoverable() {
11 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
12 | .contains(Utf8StringCodecFactory.class);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/delay/ConstantDelayFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
7 | import io.dropwizard.jackson.Jackson;
8 | import io.dropwizard.jersey.validation.Validators;
9 | import io.dropwizard.util.Duration;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.File;
13 |
14 | import jakarta.validation.Validator;
15 |
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | public class ConstantDelayFactoryTest {
19 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
20 | private final Validator validator = Validators.newValidator();
21 | private final YamlConfigurationFactory configFactory =
22 | new YamlConfigurationFactory<>(DelayFactory.class, validator, objectMapper, "dw");
23 |
24 | @Test
25 | public void shouldBuildAConstantDelayFactory() throws Exception {
26 | final File yml = new File(Resources.getResource("yaml/delay/constant.yaml").toURI());
27 | final DelayFactory factory = configFactory.build(yml);
28 | assertThat(factory)
29 | .isInstanceOf(ConstantDelayFactory.class);
30 |
31 | final ConstantDelayFactory constantDelayFactory = (ConstantDelayFactory) factory;
32 | assertThat(constantDelayFactory.getDuration())
33 | .isEqualTo(Duration.seconds(5));
34 | }
35 |
36 | @Test
37 | public void isDiscoverable() {
38 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
39 | .contains(ConstantDelayFactory.class);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/delay/DecorrelatedJitterDelayFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
7 | import io.dropwizard.jackson.Jackson;
8 | import io.dropwizard.jersey.validation.Validators;
9 | import io.dropwizard.util.Duration;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.File;
13 |
14 | import jakarta.validation.Validator;
15 |
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | public class DecorrelatedJitterDelayFactoryTest {
19 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
20 | private final Validator validator = Validators.newValidator();
21 | private final YamlConfigurationFactory configFactory =
22 | new YamlConfigurationFactory<>(DelayFactory.class, validator, objectMapper, "dw");
23 |
24 | @Test
25 | public void shouldBuildADecorrelatedJitterDelayFactory() throws Exception {
26 | final File yml = new File(Resources.getResource("yaml/delay/decorrelated-jitter.yaml").toURI());
27 | final DelayFactory factory = configFactory.build(yml);
28 | assertThat(factory)
29 | .isInstanceOf(DecorrelatedJitterDelayFactory.class);
30 |
31 | final DecorrelatedJitterDelayFactory delayFactory = (DecorrelatedJitterDelayFactory) factory;
32 | assertThat(delayFactory.getBase()).isEqualTo(1L);
33 | assertThat(delayFactory.getLowerBound()).isEqualTo(Duration.seconds(1));
34 | assertThat(delayFactory.getUpperBound()).isEqualTo(Duration.seconds(5));
35 | }
36 |
37 | @Test
38 | public void isDiscoverable() {
39 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
40 | .contains(DecorrelatedJitterDelayFactory.class);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/delay/EqualJitterDelayFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
7 | import io.dropwizard.jackson.Jackson;
8 | import io.dropwizard.jersey.validation.Validators;
9 | import io.dropwizard.util.Duration;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.File;
13 |
14 | import jakarta.validation.Validator;
15 |
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | public class EqualJitterDelayFactoryTest {
19 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
20 | private final Validator validator = Validators.newValidator();
21 | private final YamlConfigurationFactory configFactory =
22 | new YamlConfigurationFactory<>(DelayFactory.class, validator, objectMapper, "dw");
23 |
24 | @Test
25 | public void shouldBuildAnEqualJitterDelayFactory() throws Exception {
26 | final File yml = new File(Resources.getResource("yaml/delay/equal-jitter.yaml").toURI());
27 | final DelayFactory factory = configFactory.build(yml);
28 | assertThat(factory)
29 | .isInstanceOf(EqualJitterDelayFactory.class);
30 |
31 | final EqualJitterDelayFactory delayFactory = (EqualJitterDelayFactory) factory;
32 | assertThat(delayFactory.getBase()).isEqualTo(1L);
33 | assertThat(delayFactory.getLowerBound()).isEqualTo(Duration.seconds(1));
34 | assertThat(delayFactory.getUpperBound()).isEqualTo(Duration.seconds(5));
35 | }
36 |
37 | @Test
38 | public void isDiscoverable() {
39 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
40 | .contains(EqualJitterDelayFactory.class);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/delay/ExponentialDelayFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
7 | import io.dropwizard.jackson.Jackson;
8 | import io.dropwizard.jersey.validation.Validators;
9 | import io.dropwizard.util.Duration;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.File;
13 |
14 | import jakarta.validation.Validator;
15 |
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | public class ExponentialDelayFactoryTest {
19 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
20 | private final Validator validator = Validators.newValidator();
21 | private final YamlConfigurationFactory configFactory =
22 | new YamlConfigurationFactory<>(DelayFactory.class, validator, objectMapper, "dw");
23 |
24 | @Test
25 | public void shouldBuildAnExponentialDelayFactory() throws Exception {
26 | final File yml = new File(Resources.getResource("yaml/delay/exponential.yaml").toURI());
27 | final DelayFactory factory = configFactory.build(yml);
28 | assertThat(factory)
29 | .isInstanceOf(ExponentialDelayFactory.class);
30 |
31 | final ExponentialDelayFactory delayFactory = (ExponentialDelayFactory) factory;
32 | assertThat(delayFactory.getPowersOf()).isEqualTo(3);
33 | assertThat(delayFactory.getLowerBound()).isEqualTo(Duration.seconds(1));
34 | assertThat(delayFactory.getUpperBound()).isEqualTo(Duration.seconds(5));
35 | }
36 |
37 | @Test
38 | public void isDiscoverable() {
39 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
40 | .contains(ExponentialDelayFactory.class);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/delay/FullJitterDelayFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.delay;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
7 | import io.dropwizard.jackson.Jackson;
8 | import io.dropwizard.jersey.validation.Validators;
9 | import io.dropwizard.util.Duration;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.File;
13 |
14 | import jakarta.validation.Validator;
15 |
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | public class FullJitterDelayFactoryTest {
19 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
20 | private final Validator validator = Validators.newValidator();
21 | private final YamlConfigurationFactory configFactory =
22 | new YamlConfigurationFactory<>(DelayFactory.class, validator, objectMapper, "dw");
23 |
24 | @Test
25 | public void shouldBuildAFullJitterDelayFactory() throws Exception {
26 | final File yml = new File(Resources.getResource("yaml/delay/full-jitter.yaml").toURI());
27 | final DelayFactory factory = configFactory.build(yml);
28 | assertThat(factory)
29 | .isInstanceOf(FullJitterDelayFactory.class);
30 |
31 | final FullJitterDelayFactory delayFactory = (FullJitterDelayFactory) factory;
32 | assertThat(delayFactory.getBase()).isEqualTo(1L);
33 | assertThat(delayFactory.getLowerBound()).isEqualTo(Duration.seconds(1));
34 | assertThat(delayFactory.getUpperBound()).isEqualTo(Duration.seconds(5));
35 | }
36 |
37 | @Test
38 | public void isDiscoverable() {
39 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
40 | .contains(FullJitterDelayFactory.class);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/event/DefaultEventBusFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.event;
2 |
3 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.assertj.core.api.Assertions.assertThat;
7 |
8 | public class DefaultEventBusFactoryTest {
9 | @Test
10 | public void isDiscoverable() {
11 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
12 | .contains(DefaultEventBusFactory.class);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/event/DefaultEventLoopGroupProviderFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.event;
2 |
3 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.assertj.core.api.Assertions.assertThat;
7 |
8 | public class DefaultEventLoopGroupProviderFactoryTest {
9 | @Test
10 | public void isDiscoverable() {
11 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
12 | .contains(DefaultEventLoopGroupProviderFactory.class);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/health/RedisHealthCheckTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.health;
2 |
3 | import io.lettuce.core.RedisException;
4 | import org.assertj.core.api.Assertions;
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Test;
7 | import org.mockito.Mock;
8 |
9 | import static org.assertj.core.api.Assertions.assertThat;
10 | import static org.mockito.Mockito.mock;
11 | import static org.mockito.Mockito.reset;
12 | import static org.mockito.Mockito.when;
13 |
14 | public class RedisHealthCheckTest {
15 | @Mock
16 | private Pingable client = mock(Pingable.class);
17 |
18 | private RedisHealthCheck healthCheck = new RedisHealthCheck(client);
19 |
20 | @BeforeEach
21 | public void setUp() {
22 | reset(client);
23 | }
24 |
25 | @Test
26 | public void shouldReturnHealthyIfPingSucceeds() {
27 | when(client.ping()).thenReturn(RedisHealthCheck.HEALTHY_STRING);
28 |
29 | assertThat(healthCheck.check().isHealthy()).isTrue();
30 | }
31 |
32 | @Test
33 | public void shouldReturnUnhealthyIfPingFails() {
34 | when(client.ping()).thenReturn("???");
35 | assertThat(healthCheck.check().isHealthy()).isFalse();
36 | }
37 |
38 | @Test
39 | public void shouldReturnUnhealthyIfPingThrowsException() {
40 | when(client.ping()).thenThrow(new RedisException("failed for some reason"));
41 | assertThat(healthCheck.check().isHealthy()).isFalse();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/managed/RedisClientManagerTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.managed;
2 |
3 | import io.lettuce.core.AbstractRedisClient;
4 | import io.lettuce.core.api.StatefulConnection;
5 | import org.junit.jupiter.api.BeforeEach;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import static org.mockito.Mockito.mock;
9 | import static org.mockito.Mockito.reset;
10 | import static org.mockito.Mockito.verify;
11 |
12 | public class RedisClientManagerTest {
13 | private static final String NAME = "redis";
14 |
15 | private final AbstractRedisClient client = mock(AbstractRedisClient.class);
16 | private final StatefulConnection connection = mock(StatefulConnection.class);
17 |
18 | private final RedisClientManager redisClientManager = new RedisClientManager(client, connection, NAME);
19 |
20 | @BeforeEach
21 | public void setUp() throws Exception {
22 | reset(client, connection);
23 | }
24 |
25 | @Test
26 | public void stopShouldCloseClient() throws Exception {
27 | // when
28 | redisClientManager.stop();
29 |
30 | // then
31 | verify(connection).close();
32 | verify(client).shutdown();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/metrics/DefaultCommandLatencyCollectorFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.google.common.io.Resources;
6 | import io.dropwizard.configuration.YamlConfigurationFactory;
7 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
8 | import io.dropwizard.jackson.Jackson;
9 | import io.dropwizard.jersey.validation.Validators;
10 | import io.lettuce.core.metrics.DefaultCommandLatencyCollector;
11 | import org.assertj.core.data.Offset;
12 | import org.junit.jupiter.api.Test;
13 |
14 | import java.io.File;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | import jakarta.validation.Validator;
18 |
19 | import static org.assertj.core.api.Assertions.assertThat;
20 |
21 | public class DefaultCommandLatencyCollectorFactoryTest {
22 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
23 | private final Validator validator = Validators.newValidator();
24 | private final YamlConfigurationFactory configFactory =
25 | new YamlConfigurationFactory<>(CommandLatencyRecorderFactory.class, validator, objectMapper, "dw");
26 |
27 | @Test
28 | public void shouldBuildDefaultCommandLatencyCollector() throws Exception {
29 | final File yml = new File(Resources.getResource("yaml/metrics/default-command-latency-collector.yaml").toURI());
30 | final CommandLatencyRecorderFactory factory = configFactory.build(yml);
31 | assertThat(factory)
32 | .isInstanceOf(DefaultCommandLatencyCollectorFactory.class);
33 |
34 | final DefaultCommandLatencyCollectorFactory defaultCommandLatencyCollectorFactory = (DefaultCommandLatencyCollectorFactory) factory;
35 | assertThat(defaultCommandLatencyCollectorFactory.getTargetUnit())
36 | .isEqualTo(TimeUnit.SECONDS);
37 | assertThat(defaultCommandLatencyCollectorFactory.getTargetPercentiles())
38 | .contains(new double[] { 50.0D, 99.0D }, Offset.offset(0.01D));
39 | assertThat(defaultCommandLatencyCollectorFactory.isEnabled())
40 | .isTrue();
41 | assertThat(defaultCommandLatencyCollectorFactory.isLocalDistinction())
42 | .isTrue();
43 | assertThat(defaultCommandLatencyCollectorFactory.isResetLatenciesAfterEvent())
44 | .isTrue();
45 |
46 | assertThat(defaultCommandLatencyCollectorFactory.build(new MetricRegistry()))
47 | .isInstanceOf(DefaultCommandLatencyCollector.class);
48 | }
49 |
50 | @Test
51 | public void isDiscoverable() {
52 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
53 | .contains(DefaultCommandLatencyCollectorFactory.class);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/metrics/DefaultEventPublisherOptionsFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
7 | import io.dropwizard.jackson.Jackson;
8 | import io.dropwizard.jersey.validation.Validators;
9 | import io.dropwizard.util.Duration;
10 | import io.lettuce.core.event.DefaultEventPublisherOptions;
11 | import org.junit.jupiter.api.Test;
12 |
13 | import java.io.File;
14 |
15 | import jakarta.validation.Validator;
16 |
17 | import static org.assertj.core.api.Assertions.assertThat;
18 |
19 | public class DefaultEventPublisherOptionsFactoryTest {
20 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
21 | private final Validator validator = Validators.newValidator();
22 | private final YamlConfigurationFactory configFactory =
23 | new YamlConfigurationFactory<>(EventPublisherOptionsFactory.class, validator, objectMapper, "dw");
24 |
25 | @Test
26 | public void shouldBuildDefaultEventPublisherOptions() throws Exception {
27 | final File yml = new File(Resources.getResource("yaml/metrics/default-event-publisher.yaml").toURI());
28 | final EventPublisherOptionsFactory factory = configFactory.build(yml);
29 | assertThat(factory)
30 | .isInstanceOf(DefaultEventPublisherOptionsFactory.class);
31 |
32 | final DefaultEventPublisherOptionsFactory defaultEventPublisherOptionsFactory = (DefaultEventPublisherOptionsFactory) factory;
33 | assertThat(defaultEventPublisherOptionsFactory.getEventEmitInterval())
34 | .isEqualTo(Duration.seconds(5));
35 |
36 | assertThat(defaultEventPublisherOptionsFactory.build())
37 | .isInstanceOf(DefaultEventPublisherOptions.class);
38 | }
39 |
40 | @Test
41 | public void isDiscoverable() {
42 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
43 | .contains(DefaultEventPublisherOptionsFactory.class);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/metrics/DropwizardCommandLatencyRecorderTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics;
2 |
3 |
4 | import com.codahale.metrics.MetricRegistry;
5 | import com.codahale.metrics.Timer;
6 | import io.lettuce.core.protocol.CommandType;
7 | import io.netty.channel.local.LocalAddress;
8 | import org.junit.jupiter.api.Test;
9 |
10 | import java.net.SocketAddress;
11 | import java.util.Map;
12 |
13 | import static org.assertj.core.api.Assertions.assertThat;
14 |
15 |
16 | public class DropwizardCommandLatencyRecorderTest {
17 |
18 | private static final SocketAddress LOCAL_ADDRESS = new LocalAddress("localhost:1234");
19 |
20 | private static final SocketAddress REMOTE_ADDRESS = new LocalAddress("localhost:6379");
21 |
22 |
23 | @Test
24 | public void verifyMetrics() {
25 | MetricRegistry metricRegistry = new MetricRegistry();
26 | DropwizardCommandLatencyRecorder commandLatencyRecorder = new DropwizardCommandLatencyRecorder(metricRegistry, true);
27 |
28 | commandLatencyRecorder.recordCommandLatency(LOCAL_ADDRESS, REMOTE_ADDRESS, CommandType.SET, 10, 10);
29 | commandLatencyRecorder.recordCommandLatency(LOCAL_ADDRESS, REMOTE_ADDRESS, CommandType.SET, 100, 500);
30 |
31 | Map timers = metricRegistry.getTimers();
32 | Timer timer = timers.get("lettuce.command.firstresponse.SET");
33 |
34 | assertThat(timers.size()).isEqualTo(2);
35 | assertThat(timer.getCount()).isEqualTo(2);
36 | assertThat(timer.getSnapshot().getMean()).isEqualTo(55);
37 | }
38 |
39 | @Test
40 | public void disabled() {
41 | MetricRegistry metricRegistry = new MetricRegistry();
42 | DropwizardCommandLatencyRecorder commandLatencyRecorder = new DropwizardCommandLatencyRecorder(metricRegistry, false);
43 |
44 | commandLatencyRecorder.recordCommandLatency(LOCAL_ADDRESS, REMOTE_ADDRESS, CommandType.GET, 1, 10);
45 |
46 | assertThat(metricRegistry.getTimers()).isEmpty();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/metrics/event/LettuceMetricsSubscriberTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.metrics.event;
2 |
3 | import com.google.common.collect.ImmutableList;
4 | import io.dropwizard.redis.metrics.event.visitor.*;
5 | import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
6 | import io.lettuce.core.event.connection.ConnectedEvent;
7 | import io.lettuce.core.event.connection.ConnectionActivatedEvent;
8 | import io.lettuce.core.event.connection.ConnectionDeactivatedEvent;
9 | import io.lettuce.core.event.connection.DisconnectedEvent;
10 | import io.lettuce.core.event.metrics.CommandLatencyEvent;
11 | import org.junit.jupiter.api.Test;
12 |
13 | import java.util.List;
14 |
15 | import static org.mockito.Mockito.*;
16 |
17 | public class LettuceMetricsSubscriberTest {
18 | @Test
19 | public void shouldDispatchEventsToListeners() {
20 | List visitors = ImmutableList.of(
21 | mock(ClusterTopologyChangedEventVisitor.class),
22 | mock(CommandLatencyEventVisitor.class),
23 | mock(ConnectedEventVisitor.class),
24 | mock(ConnectionActivatedEventVisitor.class),
25 | mock(ConnectionDeactivatedEventVisitor.class),
26 | mock(DisconnectedEventVisitor.class)
27 | );
28 | LettuceMetricsSubscriber subscriber = new LettuceMetricsSubscriber(visitors);
29 |
30 | verifyClusterTopologyChangedEvent(subscriber, visitors);
31 | verifyCommandLatencyEvent(subscriber, visitors);
32 | verifyConnectedEvent(subscriber, visitors);
33 | verifyConnectionActivatedEvent(subscriber, visitors);
34 | verifyConnectionDeactivatedEvent(subscriber, visitors);
35 | verifyDisconnectedEvent(subscriber, visitors);
36 | for (EventVisitor visitor : visitors) {
37 | verifyNoMoreInteractions(visitor);
38 | }
39 | }
40 |
41 | private void verifyClusterTopologyChangedEvent(LettuceMetricsSubscriber subscriber, List visitors) {
42 | ClusterTopologyChangedEvent event = mock(ClusterTopologyChangedEvent.class);
43 | subscriber.accept(event);
44 |
45 | for (EventVisitor visitor : visitors) {
46 | verify(visitor, times(1)).visit(event);
47 | }
48 | }
49 |
50 | private void verifyCommandLatencyEvent(LettuceMetricsSubscriber subscriber, List visitors) {
51 | CommandLatencyEvent event = mock(CommandLatencyEvent.class);
52 | subscriber.accept(event);
53 |
54 | for (EventVisitor visitor : visitors) {
55 | verify(visitor, times(1)).visit(event);
56 | }
57 | }
58 |
59 | private void verifyConnectedEvent(LettuceMetricsSubscriber subscriber, List visitors) {
60 | ConnectedEvent event = mock(ConnectedEvent.class);
61 | subscriber.accept(event);
62 |
63 | for (EventVisitor visitor : visitors) {
64 | verify(visitor, times(1)).visit(event);
65 | }
66 | }
67 |
68 | private void verifyConnectionActivatedEvent(LettuceMetricsSubscriber subscriber, List visitors) {
69 | ConnectionActivatedEvent event = mock(ConnectionActivatedEvent.class);
70 | subscriber.accept(event);
71 |
72 | for (EventVisitor visitor : visitors) {
73 | verify(visitor, times(1)).visit(event);
74 | }
75 | }
76 |
77 | private void verifyConnectionDeactivatedEvent(LettuceMetricsSubscriber subscriber, List visitors) {
78 | ConnectionDeactivatedEvent event = mock(ConnectionDeactivatedEvent.class);
79 | subscriber.accept(event);
80 |
81 | for (EventVisitor visitor : visitors) {
82 | verify(visitor, times(1)).visit(event);
83 | }
84 | }
85 |
86 | private void verifyDisconnectedEvent(LettuceMetricsSubscriber subscriber, List visitors) {
87 | DisconnectedEvent event = mock(DisconnectedEvent.class);
88 | subscriber.accept(event);
89 |
90 | for (EventVisitor visitor : visitors) {
91 | verify(visitor, times(1)).visit(event);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/netty/DefaultEventExecutorGroupFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.netty;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.google.common.io.Resources;
6 | import io.dropwizard.configuration.YamlConfigurationFactory;
7 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
8 | import io.dropwizard.jackson.Jackson;
9 | import io.dropwizard.jersey.validation.Validators;
10 | import io.netty.util.concurrent.DefaultEventExecutorGroup;
11 | import org.junit.jupiter.api.Test;
12 |
13 | import java.io.File;
14 |
15 | import jakarta.validation.Validator;
16 |
17 | import static org.assertj.core.api.Assertions.assertThat;
18 |
19 | public class DefaultEventExecutorGroupFactoryTest {
20 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
21 | private final Validator validator = Validators.newValidator();
22 | private final YamlConfigurationFactory configFactory =
23 | new YamlConfigurationFactory<>(EventExecutorGroupFactory.class, validator, objectMapper, "dw");
24 |
25 | @Test
26 | public void shouldBuildADefaultEventExecutorGroup() throws Exception {
27 | final File yml = new File(Resources.getResource("yaml/netty/default.yaml").toURI());
28 | final EventExecutorGroupFactory factory = configFactory.build(yml);
29 | assertThat(factory)
30 | .isInstanceOf(DefaultEventExecutorGroupFactory.class);
31 |
32 | final DefaultEventExecutorGroupFactory defaultEventExecutorGroupFactory = (DefaultEventExecutorGroupFactory) factory;
33 |
34 | assertThat(defaultEventExecutorGroupFactory.build(5, "name", new MetricRegistry()))
35 | .isInstanceOf(DefaultEventExecutorGroup.class);
36 | }
37 |
38 | @Test
39 | public void isDiscoverable() {
40 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
41 | .contains(DefaultEventExecutorGroupFactory.class);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/socket/SocketOptionsFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.socket;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.Jackson;
7 | import io.dropwizard.jersey.validation.Validators;
8 | import io.dropwizard.util.Duration;
9 | import io.lettuce.core.SocketOptions;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.File;
13 |
14 | import jakarta.validation.Validator;
15 |
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | public class SocketOptionsFactoryTest {
19 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
20 | private final Validator validator = Validators.newValidator();
21 | private final YamlConfigurationFactory configFactory =
22 | new YamlConfigurationFactory<>(SocketOptionsFactory.class, validator, objectMapper, "dw");
23 |
24 | @Test
25 | public void shouldBuildASocketOptions() throws Exception {
26 | final File yml = new File(Resources.getResource("yaml/socket/socket-options.yaml").toURI());
27 | final SocketOptionsFactory factory = configFactory.build(yml);
28 |
29 | assertThat(factory.getConnectTimeout())
30 | .isEqualTo(Duration.seconds(5));
31 | assertThat(factory.isKeepAlive())
32 | .isTrue();
33 | assertThat(factory.isTcpNoDelay())
34 | .isTrue();
35 |
36 | assertThat(factory.build())
37 | .isInstanceOf(SocketOptions.class);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/ssl/SslOptionsFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.ssl;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.Jackson;
7 | import io.dropwizard.jersey.validation.Validators;
8 | import io.lettuce.core.SslOptions;
9 | import org.junit.jupiter.api.Test;
10 |
11 | import java.io.File;
12 |
13 | import jakarta.validation.Validator;
14 |
15 | import static org.assertj.core.api.Assertions.assertThat;
16 |
17 | public class SslOptionsFactoryTest {
18 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
19 | private final Validator validator = Validators.newValidator();
20 | private final YamlConfigurationFactory configFactory =
21 | new YamlConfigurationFactory<>(SslOptionsFactory.class, validator, objectMapper, "dw");
22 |
23 | @Test
24 | public void shouldSslOptions() throws Exception {
25 | final File yml = new File(Resources.getResource("yaml/ssl/ssl.yaml").toURI());
26 | final SslOptionsFactory factory = configFactory.build(yml);
27 |
28 | assertThat(factory.isEnabled())
29 | .isTrue();
30 | assertThat(factory.getSslProvider())
31 | .isEqualTo(SslOptions.DEFAULT_SSL_PROVIDER);
32 | assertThat(factory.getKeystore())
33 | .isFile();
34 | assertThat(factory.getKeystorePassword())
35 | .isEqualTo("hunter2");
36 | assertThat(factory.getTruststore())
37 | .isFile();
38 | assertThat(factory.getTruststorePassword())
39 | .isEqualTo("hunter2");
40 |
41 | assertThat(factory.build()).isNotNull();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/test/RedisClusterBundleIT.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.test;
2 |
3 | import com.github.fppt.jedismock.RedisServer;
4 | import io.dropwizard.testing.ConfigOverride;
5 | import io.dropwizard.testing.DropwizardTestSupport;
6 | import io.lettuce.core.api.StatefulRedisConnection;
7 | import org.junit.jupiter.api.AfterAll;
8 | import org.junit.jupiter.api.BeforeAll;
9 | import org.junit.jupiter.api.Test;
10 |
11 | import static org.assertj.core.api.Assertions.assertThat;
12 |
13 | public class RedisClusterBundleIT {
14 | private static final String CONFIG_PATH = "src/test/resources/yaml/config.yaml";
15 |
16 | private static final String REDIS_NODE_KEY = "redis.node.node";
17 |
18 | private static DropwizardTestSupport APP_RULE;
19 |
20 | private static RedisServer REDIS;
21 |
22 | @BeforeAll
23 | public static void setUpBeforeClass() throws Exception {
24 | REDIS = RedisServer.newRedisServer(); // bind to a random port
25 | REDIS.start();
26 |
27 | APP_RULE = new DropwizardTestSupport<>(TestApplication.class, CONFIG_PATH,
28 | ConfigOverride.config(REDIS_NODE_KEY, String.format("%s:%d", REDIS.getHost(), REDIS.getBindPort())));
29 | APP_RULE.before();
30 | }
31 |
32 | @AfterAll
33 | public static void tearDownAfterClass() throws Exception {
34 | APP_RULE.after();
35 | REDIS.stop();
36 | }
37 |
38 | @Test
39 | public void shouldHavePinged() {
40 | final StatefulRedisConnection connection = ((TestApplication) APP_RULE.getApplication()).getRedisCluster()
41 | .getConnection();
42 |
43 | assertThat(connection.sync().get("foo"))
44 | .isEqualTo("bar");
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/test/TestApplication.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.test;
2 |
3 | import io.dropwizard.core.Application;
4 | import io.dropwizard.core.setup.Bootstrap;
5 | import io.dropwizard.core.setup.Environment;
6 | import io.dropwizard.redis.RedisClientBundle;
7 | import io.dropwizard.redis.RedisClientFactory;
8 | import io.lettuce.core.api.StatefulRedisConnection;
9 |
10 | public class TestApplication extends Application {
11 |
12 | private final RedisClientBundle redisCluster =
13 | new RedisClientBundle() {
14 | @Override
15 | public RedisClientFactory getRedisClientFactory(final TestConfiguration configuration) {
16 | return configuration.getRedisClientFactory();
17 | }
18 | };
19 |
20 | @Override
21 | public void initialize(Bootstrap bootstrap) {
22 | bootstrap.addBundle(redisCluster);
23 | }
24 |
25 | @Override
26 | public void run(final TestConfiguration testConfiguration, final Environment environment) throws Exception {
27 | final StatefulRedisConnection clusterConnection = redisCluster.getConnection();
28 |
29 | clusterConnection.sync().set("foo", "bar");
30 | }
31 |
32 | public RedisClientBundle getRedisCluster() {
33 | return redisCluster;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/test/TestConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.test;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import io.dropwizard.core.Configuration;
5 | import io.dropwizard.redis.RedisClientFactory;
6 |
7 | import jakarta.validation.Valid;
8 | import jakarta.validation.constraints.NotNull;
9 |
10 | public class TestConfiguration extends Configuration {
11 | @Valid
12 | @NotNull
13 | @JsonProperty("redis")
14 | private RedisClientFactory redisClientFactory;
15 |
16 | public RedisClientFactory getRedisClientFactory() {
17 | return redisClientFactory;
18 | }
19 |
20 | public void setRedisClientFactory(final RedisClientFactory redisClientFactory) {
21 | this.redisClientFactory = redisClientFactory;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/timeout/TimeoutOptionsFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.timeout;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.Jackson;
7 | import io.dropwizard.jersey.validation.Validators;
8 | import io.dropwizard.util.Duration;
9 | import io.lettuce.core.TimeoutOptions;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.File;
13 |
14 | import jakarta.validation.Validator;
15 |
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | public class TimeoutOptionsFactoryTest {
19 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
20 | private final Validator validator = Validators.newValidator();
21 | private final YamlConfigurationFactory configFactory =
22 | new YamlConfigurationFactory<>(TimeoutOptionsFactory.class, validator, objectMapper, "dw");
23 |
24 | @Test
25 | public void shouldBuildATimeoutOptions() throws Exception {
26 | final File yml = new File(Resources.getResource("yaml/timeout/timeout-options.yaml").toURI());
27 | final TimeoutOptionsFactory factory = configFactory.build(yml);
28 |
29 | assertThat(factory.getFixedTimeout())
30 | .isEqualTo(Duration.seconds(6));
31 | assertThat(factory.isTimeoutCommands())
32 | .isTrue();
33 | assertThat(factory.isApplyConnectionTimeout())
34 | .isTrue();
35 |
36 | assertThat(factory.build())
37 | .isInstanceOf(TimeoutOptions.class);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/topology/ClusterTopologyRefreshOptionsFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.topology;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import io.dropwizard.configuration.YamlConfigurationFactory;
6 | import io.dropwizard.jackson.Jackson;
7 | import io.dropwizard.jersey.validation.Validators;
8 | import io.dropwizard.util.Duration;
9 | import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.File;
13 |
14 | import jakarta.validation.Validator;
15 |
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | public class ClusterTopologyRefreshOptionsFactoryTest {
19 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
20 | private final Validator validator = Validators.newValidator();
21 | private final YamlConfigurationFactory configFactory =
22 | new YamlConfigurationFactory<>(ClusterTopologyRefreshOptionsFactory.class, validator, objectMapper, "dw");
23 |
24 | @Test
25 | public void shouldBuildAClusterToplogyRefreshOptions() throws Exception {
26 | final File yml = new File(Resources.getResource("yaml/topology/cluster-topology-refresh-options.yaml").toURI());
27 | final ClusterTopologyRefreshOptionsFactory factory = configFactory.build(yml);
28 |
29 | assertThat(factory.isPeriodicRefreshEnabled())
30 | .isTrue();
31 | assertThat(factory.getRefreshPeriod())
32 | .isEqualTo(Duration.minutes(2));
33 | assertThat(factory.isCloseStaleConnections())
34 | .isFalse();
35 | assertThat(factory.isDynamicRefreshSources())
36 | .isFalse();
37 | assertThat(factory.getAdaptiveRefreshTriggers())
38 | .contains(ClusterTopologyRefreshOptions.RefreshTrigger.PERSISTENT_RECONNECTS);
39 | assertThat(factory.getRefreshTriggersReconnectAttempts())
40 | .isEqualTo(3);
41 |
42 | assertThat(factory.build())
43 | .isInstanceOf(ClusterTopologyRefreshOptions.class);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/uri/RedisModeURIFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.uri;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import com.google.common.net.HostAndPort;
6 | import io.dropwizard.configuration.YamlConfigurationFactory;
7 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
8 | import io.dropwizard.jackson.Jackson;
9 | import io.dropwizard.jersey.validation.Validators;
10 | import io.dropwizard.util.Duration;
11 | import io.lettuce.core.RedisURI;
12 | import org.junit.jupiter.api.Test;
13 |
14 | import java.io.File;
15 |
16 | import jakarta.validation.Validator;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 |
20 | public class RedisModeURIFactoryTest {
21 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
22 | private final Validator validator = Validators.newValidator();
23 | private final YamlConfigurationFactory configFactory =
24 | new YamlConfigurationFactory<>(RedisURIFactory.class, validator, objectMapper, "dw");
25 |
26 | @Test
27 | public void shouldBuildARedisURI() throws Exception {
28 | final File yml = new File(Resources.getResource("yaml/uri/redis-uri.yaml").toURI());
29 | final RedisURIFactory factory = configFactory.build(yml);
30 | assertThat(factory)
31 | .isInstanceOf(RedisModeURIFactory.class);
32 |
33 | final RedisModeURIFactory redisModeURIFactory = (RedisModeURIFactory) factory;
34 |
35 | assertThat(redisModeURIFactory.getNode())
36 | .isEqualTo(HostAndPort.fromParts("127.0.0.1", 6379));
37 | assertThat(redisModeURIFactory.getTimeout())
38 | .isEqualTo(Duration.seconds(90));
39 | assertThat(redisModeURIFactory.getClientName())
40 | .isEqualTo("test");
41 | assertThat(redisModeURIFactory.getPassword())
42 | .isEqualTo("hunter2");
43 | assertThat(redisModeURIFactory.isSsl())
44 | .isTrue();
45 | assertThat(redisModeURIFactory.isStartTls())
46 | .isTrue();
47 | assertThat(redisModeURIFactory.isVerifyPeer())
48 | .isTrue();
49 |
50 | assertThat(factory.build())
51 | .isInstanceOf(RedisURI.class);
52 | }
53 |
54 | @Test
55 | public void isDiscoverable() {
56 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
57 | .contains(RedisModeURIFactory.class);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/java/io/dropwizard/redis/uri/SentinelModeURIFactoryTest.java:
--------------------------------------------------------------------------------
1 | package io.dropwizard.redis.uri;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.io.Resources;
5 | import com.google.common.net.HostAndPort;
6 | import io.dropwizard.configuration.YamlConfigurationFactory;
7 | import io.dropwizard.jackson.DiscoverableSubtypeResolver;
8 | import io.dropwizard.jackson.Jackson;
9 | import io.dropwizard.jersey.validation.Validators;
10 | import io.dropwizard.redis.delay.ConstantDelayFactory;
11 | import io.dropwizard.util.Duration;
12 | import io.lettuce.core.RedisURI;
13 | import org.junit.jupiter.api.Test;
14 |
15 | import java.io.File;
16 |
17 | import jakarta.validation.Validator;
18 |
19 | import static org.assertj.core.api.Assertions.assertThat;
20 |
21 | public class SentinelModeURIFactoryTest {
22 | private final ObjectMapper objectMapper = Jackson.newObjectMapper();
23 | private final Validator validator = Validators.newValidator();
24 | private final YamlConfigurationFactory configFactory =
25 | new YamlConfigurationFactory<>(RedisURIFactory.class, validator, objectMapper, "dw");
26 |
27 | @Test
28 | public void shouldBuildASentinelRedisURI() throws Exception {
29 | final File yml = new File(Resources.getResource("yaml/uri/sentinel-redis-uri.yaml").toURI());
30 | final RedisURIFactory factory = configFactory.build(yml);
31 |
32 | assertThat(factory)
33 | .isInstanceOf(SentinelModeURIFactory.class);
34 |
35 | final SentinelModeURIFactory sentinelModeURIFactory = (SentinelModeURIFactory) factory;
36 |
37 | assertThat(sentinelModeURIFactory.getTimeout())
38 | .isEqualTo(Duration.seconds(90));
39 | assertThat(sentinelModeURIFactory.getClientName())
40 | .isEqualTo("test");
41 | assertThat(sentinelModeURIFactory.getPassword())
42 | .isEqualTo("hunter2");
43 | assertThat(sentinelModeURIFactory.getSentinels())
44 | .contains(HostAndPort.fromParts("127.0.0.1", 6389));
45 | assertThat(sentinelModeURIFactory.getSentinelMasterId())
46 | .isEqualTo("abc");
47 |
48 | assertThat(factory.build())
49 | .isInstanceOf(RedisURI.class);
50 | }
51 |
52 | @Test
53 | public void isDiscoverable() {
54 | assertThat(new DiscoverableSubtypeResolver().getDiscoveredSubtypes())
55 | .contains(SentinelModeURIFactory.class);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/resources/keystore.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dropwizard/dropwizard-redis/420d22b093e8b78539ba2bdffd403bfc33517f69/src/test/resources/keystore.p12
--------------------------------------------------------------------------------
/src/test/resources/truststore.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dropwizard/dropwizard-redis/420d22b093e8b78539ba2bdffd403bfc33517f69/src/test/resources/truststore.p12
--------------------------------------------------------------------------------
/src/test/resources/yaml/clientresources/default.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: default
3 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/codec/compression.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: compression
3 | delegatee:
4 | type: string
5 | compressionType: GZIP
6 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | redis:
3 | type: basic
4 | name: my-redis-use-case
5 | node:
6 | type: redis
7 | node: "127.0.0.1:6379"
8 | clientName: person-app
9 | redisCodec:
10 | type: string
11 | clientResources:
12 | type: default
13 | commandLatencyRecorder:
14 | type: default
15 | enabled: false
16 |
17 | server:
18 | type: simple
19 | applicationContextPath: /
20 | connector:
21 | type: http
22 | port: 0
23 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/delay/constant.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: constant
3 | duration: 5s
4 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/delay/decorrelated-jitter.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: decorrelated-jitter
3 | base: 1
4 | lowerBound: 1s
5 | upperBound: 5s
6 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/delay/equal-jitter.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: equal-jitter
3 | base: 1
4 | lowerBound: 1s
5 | upperBound: 5s
6 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/delay/exponential.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: exponential
3 | powersOf: 3
4 | lowerBound: 1s
5 | upperBound: 5s
6 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/delay/full-jitter.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: full-jitter
3 | base: 1
4 | lowerBound: 1s
5 | upperBound: 5s
6 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/metrics/default-command-latency-collector.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: default
3 | targetUnit: SECONDS
4 | targetPercentiles: [50.0, 99.0]
5 | resetLatenciesAfterEvent: true
6 | localDistinction: true
7 | enabled: true
8 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/metrics/default-event-publisher.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: default
3 | eventEmitInterval: 5s
4 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/netty/default.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: default
3 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/socket/socket-options.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | connectTimeout: 5s
3 | keepAlive: true
4 | tcpNoDelay: true
5 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/ssl/ssl.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | enabled: true
3 | keystore: src/test/resources/keystore.p12
4 | keystorePassword: hunter2
5 | truststore: src/test/resources/truststore.p12
6 | truststorePassword: hunter2
7 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/timeout/timeout-options.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | timeoutCommands: true
3 | applyConnectionTimeout: true
4 | fixedTimeout: 6s
5 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/topology/cluster-topology-refresh-options.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | periodicRefreshEnabled: true
3 | refreshPeriod: 2m
4 | closeStaleConnections: false
5 | dynamicRefreshSources: false
6 | adaptiveRefreshTriggers:
7 | - PERSISTENT_RECONNECTS
8 | refreshTriggersReconnectAttempts: 3
9 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/uri/redis-uri.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: redis
3 | node: "127.0.0.1:6379"
4 | timeout: 90s
5 | clientName: test
6 | password: hunter2
7 | ssl: true
8 | startTls: true
9 | verifyPeer: true
10 |
--------------------------------------------------------------------------------
/src/test/resources/yaml/uri/sentinel-redis-uri.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | type: sentinel
3 | timeout: 90s
4 | clientName: test
5 | password: hunter2
6 | sentinels:
7 | - "127.0.0.1:6389"
8 | sentinelMasterId: abc
9 |
--------------------------------------------------------------------------------