Skip to content

Instantly share code, notes, and snippets.

@aoudiamoncef
Last active January 9, 2023 11:00
Show Gist options
  • Save aoudiamoncef/437aa1944685bb90900db37250a266d4 to your computer and use it in GitHub Desktop.
Save aoudiamoncef/437aa1944685bb90900db37250a266d4 to your computer and use it in GitHub Desktop.
GraphQL Java Dataloader Redis generic Cachemap (Spring Boot 2 )
@Configuration
public class DataLoaderConfig {
@Autowired
private RedisCacheRepository<String, ObjectId, Home> homeByObjectIdCacheMapRepository;
@Autowired
private RedisCacheRepository<String, String, Home> homeByStringCacheMapRepository;
@Bean
public DataLoaderRegistry dataLoaderRegistry() {
final DataLoaderRegistry registry = new DataLoaderRegistry();
registry.register(HOME_BY_ID_DATALOADER, getHomeByIdDataLoader());
registry.register(HOME_BY_ADDRESS_IDENTIFIER_DATALOADER, getHomeByAddressIdentifierDataLoader());
return registry;
}
private DataLoader<ObjectId, Home> getHomeByIdDataLoader() {
final RedisCacheMap<String, ObjectId, Home> homeByObjectIdCacheMap = new RedisCacheMap<>(homeByObjectIdCacheMapRepository);
homeByObjectIdCacheMap.setRedisKey(HOMES_BY_OBJECT_IDS);
final DataLoaderOptions homeByObjectIdOptions = DataLoaderOptions.newOptions().setCacheMap(homeByObjectIdCacheMap);
return DataLoader.newDataLoader(homeByIdBatchLoader(), homeByObjectIdOptions);
}
private DataLoader<String, Home> getHomeByAddressIdentifierDataLoader() {
final RedisCacheMap<String, String, Home> homeByAddressIdentifierCacheMap = new RedisCacheMap<>(homeByStringCacheMapRepository);
homeByAddressIdentifierCacheMap.setRedisKey(HOMES_BY_ADDRESS_IDENTIFIERS);
final DataLoaderOptions homeByAddressIdentifierOptions = DataLoaderOptions.newOptions().setCacheMap(homeByAddressIdentifierCacheMap);
return DataLoader.newDataLoader(homessByAddressIdentifierBatchLoader(), homeByAddressIdentifierOptions);
}
private BatchLoader<ObjectId, Home> homeByIdBatchLoader() {
return keys -> CompletableFuture.supplyAsync(() -> homeService.findAllHomesById(keys, true));
}
private BatchLoader<String, Home> homesByAddressIdentifierBatchLoader() {
return keys -> CompletableFuture.supplyAsync(() -> homeService.findAllHomesByAddressIdentifiers(keys, true));
}
}
@Component
public class RedisCacheMap<K, U, V> implements CacheMap<U, CompletableFuture<V>> {
private K redisKey = null;
private final RedisCacheRepository<K, U, V> cache;
public RedisCacheMap(final RedisCacheRepository<K, U, V> cache) {
this.cache = cache;
}
@Override
public boolean containsKey(final U key) {
return cache.existById(redisKey, key);
}
@Override
public CompletableFuture<V> get(final U key) {
// supplyAsync method fails only with high load tests(CompletableFuture never completes)
return CompletableFuture.completedFuture(cache.findOneById(redisKey, key));
}
@Override
public CacheMap<U, CompletableFuture<V>> set(final U key, final CompletableFuture<V> value) {
value.thenAccept(object -> cache.saveOneById(redisKey, key, object));
return this;
}
@Override
public CacheMap<U, CompletableFuture<V>> delete(final U key) {
cache.deleteOneById(redisKey, key);
return this;
}
@Override
public CacheMap<U, CompletableFuture<V>> clear() {
cache.deleteAll(redisKey);
return this;
}
public K getRedisKey() {
return redisKey;
}
// Simpler way to setup multiple instances
public void setRedisKey(K redisKey) {
this.redisKey = redisKey;
}
}
@Repository
public class RedisCacheRepository<H, K, V>{
private final RedisTemplate<H, V> redisIdTemplate;
private HashOperations<H, K, V> hashOperations;
public RedisCacheRepository(final RedisTemplate<H, V> redisTemplate) {
this.redisIdTemplate = redisTemplate;
}
@PostConstruct
private void init() {
this.hashOperations = redisIdTemplate.opsForHash();
}
public void saveOneById(final H redisHash, final K key, final V value) {
hashOperations.put(redisHash, key, value);
}
public V findOneById(final H redisHash, final K key) {
return hashOperations.get(redisHash, key);
}
public Map<K, V> findAll(final H redisHash) {
return hashOperations.entries(redisHash);
}
public void updateOneById(final H redisHash, final K key, final V value) {
hashOperations.put(redisHash, key, value);
}
public Long deleteOneById(final H redisHash, final K key) {
return hashOperations.delete(redisHash, key);
}
public Long deleteAll(final H redisHash) {
return hashOperations.delete(redisHash);
}
public Boolean existById(final H redisHash, final K key) {
return hashOperations.hasKey(redisHash, key);
}
}
@Configuration
public class RedisConfig {
@Bean
@Primary
public RedisTemplate<String, Object> redisTemplate(final JedisConnectionFactory jedisConnectionFactory) {
final RedisTemplate<String, Object> template = new RedisTemplate<>();
final GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
template.setConnectionFactory(jedisConnectionFactory);
template.setDefaultSerializer(genericJackson2JsonRedisSerializer);
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(genericJackson2JsonRedisSerializer);
template.setValueSerializer(genericJackson2JsonRedisSerializer);
template.afterPropertiesSet();
createKeysIfAbsent(template);
return template;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment