Skip to content

Commit 266fb8d

Browse files
pditommasoclaude
andcommitted
Add micronaut-redis module
Micronaut cache implementation using Jedis driver, providing drop-in compatibility with the official Micronaut Redis (Lettuce) cache module. Features: - Works with @Cacheable, @cACHEpUT, @CacheInvalidate annotations - Uses Jedis driver with JedisPool for connection pooling - Same configuration namespace as official Lettuce implementation - Supports expire-after-write and expire-after-access policies - Custom expiration policy support - Async cache operations via AsyncCache 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ccaee27 commit 266fb8d

File tree

14 files changed

+1282
-0
lines changed

14 files changed

+1282
-0
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +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
8687
8788
env:
8889
GRADLE_OPTS: '-Dorg.gradle.daemon=false'

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
"lib-serde-jackson",
3535
"lib-trace",
3636
"lib-util-http",
37+
"micronaut-redis",
3738
"wave-api",
3839
"wave-utils"
3940
]

micronaut-redis/README.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Micronaut Redis Cache
2+
3+
A Micronaut cache implementation using the Jedis Redis driver, providing drop-in compatibility with the official Micronaut Redis (Lettuce) cache module.
4+
5+
## Features
6+
7+
- Works with Micronaut's `@Cacheable`, `@CachePut`, `@CacheInvalidate` annotations
8+
- Uses Jedis driver with JedisPool for connection pooling
9+
- Same configuration namespace as the official Lettuce implementation
10+
- Supports expiration policies (expire-after-write, expire-after-access)
11+
- Custom expiration policy support
12+
- Async cache operations via `AsyncCache`
13+
14+
## Installation
15+
16+
Add the dependency to your `build.gradle`:
17+
18+
```groovy
19+
dependencies {
20+
implementation 'io.seqera:micronaut-redis:1.0.0'
21+
}
22+
```
23+
24+
## Configuration
25+
26+
The module uses the same configuration as the official Micronaut Redis cache:
27+
28+
```yaml
29+
redis:
30+
caches:
31+
my-cache:
32+
expire-after-write: 1h
33+
another-cache:
34+
expire-after-access: 30m
35+
invalidate-scan-count: 100
36+
```
37+
38+
### Configuration Options
39+
40+
| Property | Type | Description |
41+
|----------|------|-------------|
42+
| `expire-after-write` | Duration | TTL after writing a value |
43+
| `expire-after-access` | Duration | TTL after accessing a value (touch-based) |
44+
| `expiration-after-write-policy` | String | Custom policy class name |
45+
| `invalidate-scan-count` | Long | SCAN batch size for invalidateAll (default: 100) |
46+
| `key-serializer` | Class | Custom key serializer |
47+
| `value-serializer` | Class | Custom value serializer |
48+
| `charset` | Charset | Character encoding for keys |
49+
50+
### Default Configuration
51+
52+
You can set defaults for all caches:
53+
54+
```yaml
55+
redis:
56+
cache:
57+
expire-after-write: 2h
58+
charset: UTF-8
59+
caches:
60+
my-cache:
61+
# inherits defaults, can override
62+
expire-after-write: 30m
63+
```
64+
65+
## Usage
66+
67+
### Provide a JedisPool Bean
68+
69+
The module requires a `JedisPool` bean to be provided by your application:
70+
71+
```java
72+
@Factory
73+
public class RedisFactory {
74+
75+
@Singleton
76+
public JedisPool jedisPool() {
77+
return new JedisPool("localhost", 6379);
78+
}
79+
}
80+
```
81+
82+
### Using with @Cacheable
83+
84+
```java
85+
@Singleton
86+
public class UserService {
87+
88+
@Cacheable("users")
89+
public User findById(Long id) {
90+
// This will be cached
91+
return userRepository.findById(id);
92+
}
93+
94+
@CachePut("users")
95+
public User update(Long id, User user) {
96+
return userRepository.save(user);
97+
}
98+
99+
@CacheInvalidate("users")
100+
public void delete(Long id) {
101+
userRepository.deleteById(id);
102+
}
103+
}
104+
```
105+
106+
### Programmatic Access
107+
108+
```java
109+
@Singleton
110+
public class CacheService {
111+
112+
private final SyncCache<JedisPool> cache;
113+
114+
public CacheService(@Named("my-cache") SyncCache<JedisPool> cache) {
115+
this.cache = cache;
116+
}
117+
118+
public void example() {
119+
// Put
120+
cache.put("key", "value");
121+
122+
// Get
123+
Optional<String> value = cache.get("key", String.class);
124+
125+
// Get with supplier
126+
String result = cache.get("key", String.class, () -> "default");
127+
128+
// Put if absent
129+
Optional<String> existing = cache.putIfAbsent("key", "value");
130+
131+
// Invalidate
132+
cache.invalidate("key");
133+
cache.invalidateAll();
134+
135+
// Async operations
136+
cache.async().get("key", String.class)
137+
.thenAccept(opt -> opt.ifPresent(System.out::println));
138+
}
139+
}
140+
```
141+
142+
### Custom Expiration Policy
143+
144+
Implement `ExpirationAfterWritePolicy` for dynamic TTL:
145+
146+
```java
147+
@Singleton
148+
public class TypeBasedExpirationPolicy implements ExpirationAfterWritePolicy {
149+
150+
@Override
151+
public long getExpirationAfterWrite(Object value) {
152+
if (value instanceof TemporaryData) {
153+
return Duration.ofMinutes(5).toMillis();
154+
}
155+
return Duration.ofHours(1).toMillis();
156+
}
157+
}
158+
```
159+
160+
Configure it:
161+
162+
```yaml
163+
redis:
164+
caches:
165+
my-cache:
166+
expiration-after-write-policy: com.example.TypeBasedExpirationPolicy
167+
```
168+
169+
## Migration from Lettuce
170+
171+
This module is designed as a drop-in replacement for `micronaut-redis-lettuce` cache. To migrate:
172+
173+
1. Replace the dependency
174+
2. Provide a `JedisPool` bean instead of Lettuce connection
175+
3. Configuration remains the same
176+
177+
## License
178+
179+
Apache License 2.0

micronaut-redis/VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.0.0

micronaut-redis/build.gradle

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2026, Seqera Labs
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
plugins {
19+
id 'io.seqera.java-library-conventions'
20+
id 'io.seqera.groovy-library-conventions'
21+
// Micronaut minimal lib
22+
// https://micronaut-projects.github.io/micronaut-gradle-plugin/latest/
23+
id "io.micronaut.minimal.library" version '4.5.3'
24+
}
25+
26+
group = 'io.seqera'
27+
version = "${project.file('VERSION').text.trim()}"
28+
29+
dependencies {
30+
// Micronaut cache core
31+
api "io.micronaut.cache:micronaut-cache-core:4.3.1"
32+
33+
// Jedis Redis client
34+
api 'redis.clients:jedis:5.1.5'
35+
36+
// Micronaut runtime
37+
implementation "io.micronaut:micronaut-runtime:${micronautCoreVersion}"
38+
implementation "io.micronaut:micronaut-context:${micronautCoreVersion}"
39+
implementation "io.micronaut:micronaut-core:${micronautCoreVersion}"
40+
41+
// JSpecify annotations
42+
compileOnly 'org.jspecify:jspecify:1.0.0'
43+
44+
// Groovy support for compilation
45+
compileOnly "io.micronaut:micronaut-inject-groovy:${micronautCoreVersion}"
46+
47+
// Test dependencies
48+
testImplementation testFixtures(project(':lib-fixtures-redis'))
49+
testImplementation "io.micronaut:micronaut-inject-groovy:${micronautCoreVersion}"
50+
testImplementation "io.micronaut.test:micronaut-test-spock:${micronautTestVersion}"
51+
testImplementation 'org.testcontainers:testcontainers:1.20.6'
52+
}
53+
54+
test {
55+
useJUnitPlatform()
56+
}
57+
58+
micronaut {
59+
version '4.8.3'
60+
runtime("netty")
61+
processing {
62+
incremental(true)
63+
}
64+
importMicronautPlatform = false
65+
}

0 commit comments

Comments
 (0)