@@ -54,104 +54,12 @@ record MaterializationInfo(
5454
5555### In-Memory (Testing/Development)
5656
57- ``` java
58- public class InMemoryMaterializationRepository implements MaterializationRepository {
59- private final Map<String , Map<String , MaterializationInfo > > storage = new ConcurrentHashMap<> ();
60-
61- @Override
62- public CompletableFuture<Map<String , MaterializationInfo > > loadMaterializedAssignmentsForUnit (
63- String unit , String materialization ) {
64- return CompletableFuture . supplyAsync(() - > {
65- Map<String , MaterializationInfo > unitAssignments = storage. get(unit);
66- if (unitAssignments == null || ! unitAssignments. containsKey(materialization)) {
67- return Map . of();
68- }
69- return Map . of(materialization, unitAssignments. get(materialization));
70- });
71- }
72-
73- @Override
74- public CompletableFuture<Void > storeAssignment (
75- String unit , Map<String , MaterializationInfo > assignments ) {
76- return CompletableFuture . runAsync(() - > {
77- storage. compute(unit, (key, existing) - > {
78- if (existing == null ) {
79- return new ConcurrentHashMap<> (assignments);
80- }
81- existing. putAll(assignments);
82- return existing;
83- });
84- });
85- }
86-
87- @Override
88- public void close () {
89- storage. clear();
90- }
91- }
92- ```
93-
94- ### Redis (Production)
95-
96- ``` java
97- public class RedisMaterializationRepository implements MaterializationRepository {
98- private final JedisPool jedisPool;
99- private final ObjectMapper objectMapper = new ObjectMapper ();
100- private static final int TTL_SECONDS = 90 * 24 * 60 * 60 ; // 90 days
101-
102- public RedisMaterializationRepository (JedisPool jedisPool ) {
103- this . jedisPool = jedisPool;
104- }
105-
106- @Override
107- public CompletableFuture<Map<String , MaterializationInfo > > loadMaterializedAssignmentsForUnit (
108- String unit , String materialization ) {
109- return CompletableFuture . supplyAsync(() - > {
110- try (var jedis = jedisPool. getResource()) {
111- String key = " sticky:" + unit + " :" + materialization;
112- String value = jedis. get(key);
113-
114- if (value == null ) return Map . of();
115-
116- // Renew TTL on read (matching Confidence behavior)
117- jedis. expire(key, TTL_SECONDS );
118-
119- MaterializationInfo info = objectMapper. readValue(value, MaterializationInfo . class);
120- return Map . of(materialization, info);
121- } catch (Exception e) {
122- throw new RuntimeException (" Failed to load from Redis" , e);
123- }
124- });
125- }
126-
127- @Override
128- public CompletableFuture<Void > storeAssignment (
129- String unit , Map<String , MaterializationInfo > assignments ) {
130- return CompletableFuture . runAsync(() - > {
131- try (var jedis = jedisPool. getResource()) {
132- for (var entry : assignments. entrySet()) {
133- String key = " sticky:" + unit + " :" + entry. getKey();
134- String value = objectMapper. writeValueAsString(entry. getValue());
135- jedis. setex(key, TTL_SECONDS , value);
136- }
137- } catch (Exception e) {
138- // Don't fail resolve on storage errors
139- System . err. println(" Failed to store to Redis: " + e. getMessage());
140- }
141- });
142- }
143-
144- @Override
145- public void close () {
146- jedisPool. close();
147- }
148- }
149- ```
57+ [ Here is an example] ( src/test/java/com/spotify/confidence/InMemoryMaterializationRepoExample.java ) on how to implement a simple in-memory ` MaterializationRepository ` . The same approach can be used with other more persistent storages (like Redis or similar) which is highly recommended for production use cases.
15058
151- ### Usage
59+ #### Usage
15260
15361``` java
154- MaterializationRepository repository = new RedisMaterializationRepository (jedisPool );
62+ MaterializationRepository repository = new InMemoryMaterializationRepoExample ( );
15563
15664OpenFeatureLocalResolveProvider provider = new OpenFeatureLocalResolveProvider (
15765 apiSecret,
@@ -174,7 +82,7 @@ OpenFeatureLocalResolveProvider provider = new OpenFeatureLocalResolveProvider(
17482| ----------| ----------| ------------|
17583| ** RemoteResolverFallback** (default) | Most apps | Simple, managed by Confidence. Network calls when needed. |
17684| ** MaterializationRepository** (in-memory) | Single-instance apps, testing | Fast, no network. Lost on restart. |
177- | ** MaterializationRepository** (Redis/DB) | High-traffic apps, offline scenarios | No network calls. Requires storage infra. |
85+ | ** MaterializationRepository** (Redis/DB) | Distributed/Multi instance apps | No network calls. Requires storage infra. |
17886
17987** Start with the default.** Only implement custom storage if you need to eliminate network calls or work offline.
18088
0 commit comments