3030/**
3131 * A thread-safe, versioned store for {@link FeatureFlag} objects backed by Redis. Also
3232 * supports an optional in-memory cache configuration that can be used to improve performance.
33- *
3433 */
3534public class RedisFeatureStore implements FeatureStore {
3635 private static final Logger logger = LoggerFactory .getLogger (RedisFeatureStore .class );
@@ -47,9 +46,9 @@ public class RedisFeatureStore implements FeatureStore {
4746 * Creates a new store instance that connects to Redis with the provided host, port, prefix, and cache timeout. Uses a default
4847 * connection pool configuration.
4948 *
50- * @param host the host for the Redis connection
51- * @param port the port for the Redis connection
52- * @param prefix a namespace prefix for all keys stored in Redis
49+ * @param host the host for the Redis connection
50+ * @param port the port for the Redis connection
51+ * @param prefix a namespace prefix for all keys stored in Redis
5352 * @param cacheTimeSecs an optional timeout for the in-memory cache. If set to 0, no in-memory caching will be performed
5453 * @deprecated as of 1.1. Please use the {@link RedisFeatureStoreBuilder#build()} for a more flexible way of constructing a {@link RedisFeatureStore}.
5554 */
@@ -62,8 +61,8 @@ public RedisFeatureStore(String host, int port, String prefix, long cacheTimeSec
6261 * Creates a new store instance that connects to Redis with the provided URI, prefix, and cache timeout. Uses a default
6362 * connection pool configuration.
6463 *
65- * @param uri the URI for the Redis connection
66- * @param prefix a namespace prefix for all keys stored in Redis
64+ * @param uri the URI for the Redis connection
65+ * @param prefix a namespace prefix for all keys stored in Redis
6766 * @param cacheTimeSecs an optional timeout for the in-memory cache. If set to 0, no in-memory caching will be performed
6867 * @deprecated as of 1.1. Please use the {@link RedisFeatureStoreBuilder#build()} for a more flexible way of constructing a {@link RedisFeatureStore}.
6968 */
@@ -75,11 +74,11 @@ public RedisFeatureStore(URI uri, String prefix, long cacheTimeSecs) {
7574 /**
7675 * Creates a new store instance that connects to Redis with the provided host, port, prefix, cache timeout, and connection pool settings.
7776 *
78- * @param host the host for the Redis connection
79- * @param port the port for the Redis connection
80- * @param prefix a namespace prefix for all keys stored in Redis
77+ * @param host the host for the Redis connection
78+ * @param port the port for the Redis connection
79+ * @param prefix a namespace prefix for all keys stored in Redis
8180 * @param cacheTimeSecs an optional timeout for the in-memory cache. If set to 0, no in-memory caching will be performed
82- * @param poolConfig an optional pool config for the Jedis connection pool
81+ * @param poolConfig an optional pool config for the Jedis connection pool
8382 * @deprecated as of 1.1. Please use the {@link RedisFeatureStoreBuilder#build()} for a more flexible way of constructing a {@link RedisFeatureStore}.
8483 */
8584 @ Deprecated
@@ -93,10 +92,10 @@ public RedisFeatureStore(String host, int port, String prefix, long cacheTimeSec
9392 /**
9493 * Creates a new store instance that connects to Redis with the provided URI, prefix, cache timeout, and connection pool settings.
9594 *
96- * @param uri the URI for the Redis connection
97- * @param prefix a namespace prefix for all keys stored in Redis
95+ * @param uri the URI for the Redis connection
96+ * @param prefix a namespace prefix for all keys stored in Redis
9897 * @param cacheTimeSecs an optional timeout for the in-memory cache. If set to 0, no in-memory caching will be performed
99- * @param poolConfig an optional pool config for the Jedis connection pool
98+ * @param poolConfig an optional pool config for the Jedis connection pool
10099 * @deprecated as of 1.1. Please use the {@link RedisFeatureStoreBuilder#build()} for a more flexible way of constructing a {@link RedisFeatureStore}.
101100 */
102101 @ Deprecated
@@ -109,7 +108,7 @@ public RedisFeatureStore(URI uri, String prefix, long cacheTimeSecs, JedisPoolCo
109108
110109 /**
111110 * Creates a new store instance that connects to Redis based on the provided {@link RedisFeatureStoreBuilder}.
112- *
111+ * <p>
113112 * See the {@link RedisFeatureStoreBuilder} for information on available configuration options and what they do.
114113 *
115114 * @param builder the configured builder to construct the store with.
@@ -127,7 +126,6 @@ protected RedisFeatureStore(RedisFeatureStoreBuilder builder) {
127126
128127 /**
129128 * Creates a new store instance that connects to Redis with a default connection (localhost port 6379) and no in-memory cache.
130- *
131129 */
132130 public RedisFeatureStore () {
133131 pool = new JedisPool (getPoolConfig (), "localhost" );
@@ -168,8 +166,9 @@ public Optional<FeatureFlag> load(String key) throws Exception {
168166 /**
169167 * Configures the instance to use a "refresh after write" cache. This will not automatically evict stale values, allowing them to be returned if failures
170168 * occur when updating them. Optionally set the cache to refresh values asynchronously, which always returns the previously cached value immediately.
169+ *
171170 * @param cacheTimeSecs the length of time in seconds, after a {@link FeatureFlag} value is created that it should be refreshed.
172- * @param asyncRefresh makes the refresh asynchronous or not.
171+ * @param asyncRefresh makes the refresh asynchronous or not.
173172 */
174173 private void createRefreshCache (long cacheTimeSecs , boolean asyncRefresh ) {
175174 ThreadFactory threadFactory = new ThreadFactoryBuilder ().setNameFormat (CACHE_REFRESH_THREAD_POOL_NAME_FORMAT ).setDaemon (true ).build ();
@@ -184,6 +183,7 @@ private void createRefreshCache(long cacheTimeSecs, boolean asyncRefresh) {
184183
185184 /**
186185 * Configures the instance to use an "expire after write" cache. This will evict stale values and block while loading the latest from Redis.
186+ *
187187 * @param cacheTimeSecs the length of time in seconds, after a {@link FeatureFlag} value is created that it should be automatically removed.
188188 */
189189 private void createExpiringCache (long cacheTimeSecs ) {
@@ -234,15 +234,16 @@ public FeatureFlag get(String key) {
234234 @ Override
235235 public Map <String , FeatureFlag > all () {
236236 try (Jedis jedis = pool .getResource ()) {
237- Map <String ,String > featuresJson = jedis .hgetAll (featuresKey ());
237+ Map <String , String > featuresJson = jedis .hgetAll (featuresKey ());
238238 Map <String , FeatureFlag > result = new HashMap <>();
239239 Gson gson = new Gson ();
240240
241- Type type = new TypeToken <FeatureFlag >() {}.getType ();
241+ Type type = new TypeToken <FeatureFlag >() {
242+ }.getType ();
242243
243244 for (Map .Entry <String , String > entry : featuresJson .entrySet ()) {
244- FeatureFlag featureFlag = gson .fromJson (entry .getValue (), type );
245- if (!featureFlag .isDeleted ()){
245+ FeatureFlag featureFlag = gson .fromJson (entry .getValue (), type );
246+ if (!featureFlag .isDeleted ()) {
246247 result .put (entry .getKey (), featureFlag );
247248 }
248249 }
@@ -264,7 +265,7 @@ public void init(Map<String, FeatureFlag> features) {
264265
265266 t .del (featuresKey ());
266267
267- for (FeatureFlag f : features .values ()) {
268+ for (FeatureFlag f : features .values ()) {
268269 t .hset (featuresKey (), f .getKey (), gson .toJson (f ));
269270 }
270271
@@ -276,7 +277,7 @@ public void init(Map<String, FeatureFlag> features) {
276277 * Deletes the feature associated with the specified key, if it exists and its version
277278 * is less than or equal to the specified version.
278279 *
279- * @param key the key of the feature to be deleted
280+ * @param key the key of the feature to be deleted
280281 * @param version the version for the delete operation
281282 */
282283 @ Override
@@ -287,7 +288,7 @@ public void delete(String key, int version) {
287288 jedis = pool .getResource ();
288289 jedis .watch (featuresKey ());
289290
290- FeatureFlag feature = getRedis (key );
291+ FeatureFlag feature = getRedis (key , jedis );
291292
292293 if (feature != null && feature .getVersion () >= version ) {
293294 logger .warn ("Attempted to delete flag: " + key + " version: " + feature .getVersion () +
@@ -303,8 +304,7 @@ public void delete(String key, int version) {
303304 if (cache != null ) {
304305 cache .invalidate (key );
305306 }
306- }
307- finally {
307+ } finally {
308308 if (jedis != null ) {
309309 jedis .unwatch ();
310310 jedis .close ();
@@ -327,7 +327,7 @@ public void upsert(String key, FeatureFlag feature) {
327327 Gson gson = new Gson ();
328328 jedis .watch (featuresKey ());
329329
330- FeatureFlag f = getRedis (key );
330+ FeatureFlag f = getRedis (key , jedis );
331331
332332 if (f != null && f .getVersion () >= feature .getVersion ()) {
333333 logger .warn ("Attempted to update flag: " + key + " version: " + f .getVersion () +
@@ -368,6 +368,7 @@ public boolean initialized() {
368368
369369 /**
370370 * Releases all resources associated with the store. The store must no longer be used once closed.
371+ *
371372 * @throws IOException
372373 */
373374 public void close () throws IOException {
@@ -404,24 +405,29 @@ private Boolean getInit() {
404405 }
405406
406407 private FeatureFlag getRedis (String key ) {
407- try (Jedis jedis = pool .getResource ()){
408- Gson gson = new Gson ();
409- String featureJson = jedis .hget (featuresKey (), key );
408+ try (Jedis jedis = pool .getResource ()) {
409+ return getRedis (key , jedis );
410+ }
411+ }
410412
411- if (featureJson == null ) {
412- logger .debug ("[get] Key: " + key + " not found in feature store. Returning null" );
413- return null ;
414- }
413+ private FeatureFlag getRedis (String key , Jedis jedis ) {
414+ Gson gson = new Gson ();
415+ String featureJson = jedis .hget (featuresKey (), key );
415416
416- Type type = new TypeToken <FeatureFlag >() {}.getType ();
417- FeatureFlag f = gson .fromJson (featureJson , type );
417+ if (featureJson == null ) {
418+ logger .debug ("[get] Key: " + key + " not found in feature store. Returning null" );
419+ return null ;
420+ }
418421
419- if (f .isDeleted ()) {
420- logger .debug ("[get] Key: " + key + " has been deleted. Returning null" );
421- return null ;
422- }
423- return f ;
422+ Type type = new TypeToken <FeatureFlag >() {
423+ }.getType ();
424+ FeatureFlag f = gson .fromJson (featureJson , type );
425+
426+ if (f .isDeleted ()) {
427+ logger .debug ("[get] Key: " + key + " has been deleted. Returning null" );
428+ return null ;
424429 }
430+ return f ;
425431 }
426432
427433 private static JedisPoolConfig getPoolConfig () {
0 commit comments