Reputation: 61
I am storing a Cart in Redis using Spring Data Redis for a specific time. An expiration property annotated with @TimeToLive sets the time to live for the Cart object as described by the code below.
I have set KeyExpirationEventMessageListener
type to listen to the expiration event in order to process additional work at the expiration event. I was able to fetch the key from the triggered event of the expiration object and I am trying to access it or its phantom object at the expiry time using the spring data repository but with no result.It returns an empty object which means that the original obeject is likely been deleted. I don't know if it is the proper way to do it.But, is there a way to fetch the expiry object at expiration or just before it gets deleted to process motre work?
@RedisHash("cart")
public class Cart implements Serializable {
@Id
@Indexed
private String id;
private long customerId;
private Set<CartLine> lines = new HashSet<>();
@TimeToLive
private long expiration;
}
public interface ShoppingCartRepository extends CrudRepository<Cart, String> {
}
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
private RedisTemplate<?, ?> redisTemplate;
private ShoppingCartRepository repository;
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer,
RedisTemplate redisTemplate, ShoppingCartRepository repository) {
super(listenerContainer);
this.redisTemplate = redisTemplate;
this.repository = repository;
}
@Override
public void onMessage(Message message, byte[] pattern) {
String key = new String(message.getBody());
try {
String id = extractId(key);
Optional<ShoppingCart> cart = repository.findById(id);
} catch(Exception e) {
logger.info("something went wrong ====> " + e.getStackTrace());
}
}
private String extractId(String key){
String keyPrefix = ShoppingCart.class.getAnnotation(RedisHash.class).value();
return key.substring((keyPrefix + ":").length());
}
}
Upvotes: 0
Views: 3258
Reputation: 21
Example using Spring boot 2.3.4.RELEASE
@RedisHash("cart")
@AllArgsConstructor
@Getter
@Setter
public class Cart implements Serializable {
@Id
@Indexed
private String id;
private String customerName;
@TimeToLive
private long expiration;
}
public interface ShoppingCartRepository extends CrudRepository<Cart, String> {
}
@SpringBootApplication
@EnableRedisRepositories(enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP)
public class RedisExpirationApplication {
public static void main(String[] args) {
SpringApplication.run(RedisExpirationApplication.class, args);
}
@Bean
public CommandLineRunner run(ShoppingCartRepository shoppingCartRepository) {
return args -> {
// TTL 1 second
shoppingCartRepository.save(new Cart("some-id", "My Customer Name", 1));
// wait 5 seconds
Thread.sleep(5000L);
};
}
@Component
public class CartListener {
// need to enable redis notifications, inside redis-cli type:
// config set notify-keyspace-events KEA
@EventListener
public void anything(RedisKeyExpiredEvent<Cart> expiredCart) {
Cart cart = (Cart) expiredCart.getValue();
System.out.println(cart.getId());
System.out.println(cart.getCustomerName());
}
}
}
Upvotes: 2
Reputation: 842
There was once a use case in my scenario, you can actually use RedisKeyExpiredEvent,
You can proceed with the following implementaion.
@SpringBootApplication
@EnableRedisRepositories(considerNestedRepositories = true, enableKeyspaceEvents = EnableKeyspaceEvents.ON_STARTUP)
static class Config {
/**
* An {@link ApplicationListener} that captures {@link RedisKeyExpiredEvent}s and just prints the value to the
* console.
*
* @return
*/
@Bean
ApplicationListener<RedisKeyExpiredEvent<Person>> eventListener() {
return event -> {
System.out.println(String.format("Received expire event for key=%s with value %s.",
new String(event.getSource()), event.getValue()));
};
}
}
You can find the sample implementation at [1].
Upvotes: 0