Skip to content

Commit d3a4ec8

Browse files
pditommasoclaude
andcommitted
Rename micronaut-redis to micronaut-cache-redis
- Rename module directory and update all references - Add trace logging to RedisCache for debugging key operations - Add changelog.txt 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 266fb8d commit d3a4ec8

File tree

15 files changed

+102
-4
lines changed

15 files changed

+102
-4
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ jobs:
8383
bash publish.sh lib-serde-moshi
8484
bash publish.sh lib-serde-jackson
8585
bash publish.sh lib-trace
86-
bash publish.sh micronaut-redis
86+
bash publish.sh micronaut-cache-redis
8787
8888
env:
8989
GRADLE_OPTS: '-Dorg.gradle.daemon=false'

.github/workflows/generate-submit-dependencies.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
"lib-serde-jackson",
3535
"lib-trace",
3636
"lib-util-http",
37-
"micronaut-redis",
37+
"micronaut-cache-redis",
3838
"wave-api",
3939
"wave-utils"
4040
]
Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Add the dependency to your `build.gradle`:
1717

1818
```groovy
1919
dependencies {
20-
implementation 'io.seqera:micronaut-redis:1.0.0'
20+
implementation 'io.seqera:micronaut-cache-redis:1.0.0'
2121
}
2222
```
2323

@@ -139,6 +139,67 @@ public class CacheService {
139139
}
140140
```
141141

142+
### Custom Value Serializer
143+
144+
The default serializer uses JDK serialization, which requires cached objects to implement `Serializable`. For objects that don't implement `Serializable` (e.g., generated DTOs), you can use a JSON-based serializer.
145+
146+
Create a Jackson serializer:
147+
148+
```java
149+
@Singleton
150+
public class JacksonObjectSerializer implements ObjectSerializer {
151+
152+
@Inject
153+
private ObjectMapper objectMapper;
154+
155+
@Override
156+
public Optional<byte[]> serialize(Object object) {
157+
if (object == null) {
158+
return Optional.empty();
159+
}
160+
try {
161+
return Optional.of(objectMapper.writeValueAsBytes(object));
162+
} catch (IOException e) {
163+
throw new RuntimeException("Failed to serialize object", e);
164+
}
165+
}
166+
167+
@Override
168+
public <T> Optional<T> deserialize(byte[] bytes, Class<T> requiredType) {
169+
if (bytes == null || bytes.length == 0) {
170+
return Optional.empty();
171+
}
172+
try {
173+
return Optional.ofNullable(objectMapper.readValue(bytes, requiredType));
174+
} catch (IOException e) {
175+
throw new RuntimeException("Failed to deserialize object", e);
176+
}
177+
}
178+
179+
@Override
180+
public <T> Optional<T> deserialize(byte[] bytes, Argument<T> requiredType) {
181+
if (bytes == null || bytes.length == 0) {
182+
return Optional.empty();
183+
}
184+
try {
185+
return Optional.ofNullable(objectMapper.readValue(bytes,
186+
objectMapper.constructType(requiredType.asType())));
187+
} catch (IOException e) {
188+
throw new RuntimeException("Failed to deserialize object", e);
189+
}
190+
}
191+
}
192+
```
193+
194+
Configure it:
195+
196+
```yaml
197+
redis:
198+
caches:
199+
my-cache:
200+
value-serializer: com.example.JacksonObjectSerializer
201+
```
202+
142203
### Custom Expiration Policy
143204

144205
Implement `ExpirationAfterWritePolicy` for dynamic TTL:
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# micronaut-cache-redis changelog
2+
3+
1.0.0 - 8 Jan 2026
4+
- Initial release of micronaut-cache-redis
5+
- Micronaut cache implementation using Jedis Redis driver
6+
- Drop-in compatibility with official Micronaut Redis (Lettuce) cache module
7+
- Support for @Cacheable, @CachePut, @CacheInvalidate annotations
8+
- JedisPool-based connection pooling
9+
- Expiration policies: expire-after-write, expire-after-access
10+
- Custom ExpirationAfterWritePolicy support for dynamic TTL
11+
- AsyncCache support via CompletableFuture
12+
- Configurable key and value serializers
13+
- Same configuration namespace as official Lettuce implementation

micronaut-redis/src/main/java/io/seqera/cache/redis/AbstractRedisCacheConfiguration.java renamed to micronaut-cache-redis/src/main/java/io/seqera/cache/redis/AbstractRedisCacheConfiguration.java

File renamed without changes.

micronaut-redis/src/main/java/io/seqera/cache/redis/DefaultRedisCacheConfiguration.java renamed to micronaut-cache-redis/src/main/java/io/seqera/cache/redis/DefaultRedisCacheConfiguration.java

File renamed without changes.

micronaut-redis/src/main/java/io/seqera/cache/redis/RedisCache.java renamed to micronaut-cache-redis/src/main/java/io/seqera/cache/redis/RedisCache.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
import redis.clients.jedis.params.SetParams;
3838
import redis.clients.jedis.resps.ScanResult;
3939

40+
import org.slf4j.Logger;
41+
import org.slf4j.LoggerFactory;
42+
4043
import java.time.Duration;
4144
import java.util.List;
4245
import java.util.Optional;
@@ -55,6 +58,8 @@
5558
@Requires(classes = SyncCache.class)
5659
public class RedisCache implements SyncCache<JedisPool>, AutoCloseable {
5760

61+
private static final Logger log = LoggerFactory.getLogger(RedisCache.class);
62+
5863
private final JedisPool jedisPool;
5964
private final ObjectSerializer keySerializer;
6065
private final ObjectSerializer valueSerializer;
@@ -133,22 +138,26 @@ public JedisPool getNativeCache() {
133138
@NonNull
134139
@Override
135140
public <T> Optional<T> get(@NonNull Object key, @NonNull Argument<T> requiredType) {
141+
log.trace("Cache '{}' GET key={}", getName(), key);
136142
byte[] serializedKey = serializeKey(key);
137143
try (Jedis jedis = jedisPool.getResource()) {
138144
byte[] data = jedis.get(serializedKey);
139145
if (expireAfterAccess != null && data != null) {
140146
jedis.pexpire(serializedKey, expireAfterAccess);
141147
}
142148
if (data != null) {
149+
log.trace("Cache '{}' HIT key={}", getName(), key);
143150
return valueSerializer.deserialize(data, requiredType);
144151
}
152+
log.trace("Cache '{}' MISS key={}", getName(), key);
145153
return Optional.empty();
146154
}
147155
}
148156

149157
@NonNull
150158
@Override
151159
public <T> T get(@NonNull Object key, @NonNull Argument<T> requiredType, @NonNull Supplier<T> supplier) {
160+
log.trace("Cache '{}' GET-WITH-SUPPLIER key={}", getName(), key);
152161
byte[] serializedKey = serializeKey(key);
153162
try (Jedis jedis = jedisPool.getResource()) {
154163
byte[] data = jedis.get(serializedKey);
@@ -158,11 +167,13 @@ public <T> T get(@NonNull Object key, @NonNull Argument<T> requiredType, @NonNul
158167
if (expireAfterAccess != null) {
159168
jedis.pexpire(serializedKey, expireAfterAccess);
160169
}
170+
log.trace("Cache '{}' HIT key={}", getName(), key);
161171
return deserialized.get();
162172
}
163173
}
164174
}
165175

176+
log.trace("Cache '{}' MISS key={}, invoking supplier", getName(), key);
166177
T value = supplier.get();
167178
putValue(serializedKey, value);
168179
return value;
@@ -172,25 +183,30 @@ public <T> T get(@NonNull Object key, @NonNull Argument<T> requiredType, @NonNul
172183
@Override
173184
@SuppressWarnings("unchecked")
174185
public <T> Optional<T> putIfAbsent(@NonNull Object key, @NonNull T value) {
186+
log.trace("Cache '{}' PUT-IF-ABSENT key={}", getName(), key);
175187
byte[] serializedKey = serializeKey(key);
176188
try (Jedis jedis = jedisPool.getResource()) {
177189
byte[] existingData = jedis.get(serializedKey);
178190
if (existingData != null) {
191+
log.trace("Cache '{}' PUT-IF-ABSENT key={} already exists, returning existing value", getName(), key);
179192
return valueSerializer.deserialize(existingData, Argument.of((Class<T>) value.getClass()));
180193
}
194+
log.trace("Cache '{}' PUT-IF-ABSENT key={} storing new value", getName(), key);
181195
putValue(serializedKey, value);
182196
return Optional.empty();
183197
}
184198
}
185199

186200
@Override
187201
public void put(@NonNull Object key, @NonNull Object value) {
202+
log.trace("Cache '{}' PUT key={}", getName(), key);
188203
byte[] serializedKey = serializeKey(key);
189204
putValue(serializedKey, value);
190205
}
191206

192207
@Override
193208
public void invalidate(@NonNull Object key) {
209+
log.trace("Cache '{}' INVALIDATE key={}", getName(), key);
194210
byte[] serializedKey = serializeKey(key);
195211
try (Jedis jedis = jedisPool.getResource()) {
196212
jedis.del(serializedKey);
@@ -199,20 +215,25 @@ public void invalidate(@NonNull Object key) {
199215

200216
@Override
201217
public void invalidateAll() {
218+
log.trace("Cache '{}' INVALIDATE-ALL pattern={}", getName(), getKeysPattern());
202219
String pattern = getKeysPattern();
203220
try (Jedis jedis = jedisPool.getResource()) {
204221
ScanParams params = new ScanParams()
205222
.match(pattern)
206223
.count(invalidateScanCount.intValue());
207224
String cursor = ScanParams.SCAN_POINTER_START;
225+
int totalDeleted = 0;
208226
do {
209227
ScanResult<byte[]> scanResult = jedis.scan(cursor.getBytes(redisCacheConfiguration.getCharset()), params);
210228
List<byte[]> keys = scanResult.getResult();
211229
if (!keys.isEmpty()) {
212230
jedis.del(keys.toArray(new byte[0][]));
231+
totalDeleted += keys.size();
232+
log.trace("Cache '{}' INVALIDATE-ALL deleted {} keys in this batch", getName(), keys.size());
213233
}
214234
cursor = scanResult.getCursor();
215235
} while (!ScanParams.SCAN_POINTER_START.equals(cursor));
236+
log.trace("Cache '{}' INVALIDATE-ALL completed, total keys deleted: {}", getName(), totalDeleted);
216237
}
217238
}
218239

@@ -263,11 +284,14 @@ protected <T> void putValue(byte[] serializedKey, T value) {
263284
byte[] bytes = serialized.get();
264285
if (expireAfterWritePolicy != null) {
265286
long ttl = expireAfterWritePolicy.getExpirationAfterWrite(value);
287+
log.trace("Cache '{}' storing value with TTL={}ms, size={} bytes", getName(), ttl, bytes.length);
266288
jedis.psetex(serializedKey, ttl, bytes);
267289
} else {
290+
log.trace("Cache '{}' storing value without TTL, size={} bytes", getName(), bytes.length);
268291
jedis.set(serializedKey, bytes);
269292
}
270293
} else {
294+
log.trace("Cache '{}' value serialization returned empty, deleting key", getName());
271295
jedis.del(serializedKey);
272296
}
273297
}

micronaut-redis/src/main/java/io/seqera/cache/redis/RedisCacheConfiguration.java renamed to micronaut-cache-redis/src/main/java/io/seqera/cache/redis/RedisCacheConfiguration.java

File renamed without changes.

0 commit comments

Comments
 (0)