spring-projects / spring-data-geode

Spring Data support for Apache Geode
Apache License 2.0
51 stars 39 forks source link

Spring Cache Abstraction annotations do not trigger CQ [DATAGEODE-50] #70

Closed spring-projects-issues closed 6 years ago

spring-projects-issues commented 6 years ago

John Blum opened DATAGEODE-50 and commented

When implementing a CQ, it does not trigger when a method is annotated with @Cachable or @CachePut. However, a CQ is triggered when a method is annotated with @CacheEvict. This should be consistent and a @Cachable or @CachePut annotated service method should trigger a CQ.

Sample code can be found here:

https://github.com/pivotal-Jammy-Louie/PCC-Pizza

Scenario:

    @Cacheable(value = "PizzaOrder")
    public PizzaOrder getPizzaOrder(long pizzaOrderId){
        this.simulateSlowService();
        return this.pizzaOrderRepository.findById(pizzaOrderId).orElse(null);
    }

    @CachePut(value = "PizzaOrder")
    public PizzaOrder createOrder (long customerId, long pizzaId){
        Customer customer = this.customerRepository.findById(customerId).orElse(null);
        Pizza pizza = this.pizzaRepository.findById(pizzaId).get();
        PizzaOrder order = new PizzaOrder(customer, pizza);
        return this.pizzaOrderRepository.save(order);
    }

    @CacheEvict(value = "PizzaOrder")
    public PizzaOrder completePizzaOrder(long pizzaOrderId){
        PizzaOrder pizzaOrder = this.pizzaOrderGemfireRepository.findById(pizzaOrderId).orElseGet(()->this.getPizzaOrder(pizzaOrderId));
        pizzaOrder.setOrderComplete(true);
        return this.pizzaOrderRepository.save(pizzaOrder);
    }

When the method completePizzaOrder is invoked I can see that the CQ is triggered but the other annotations do not trigger the CQ.

If I perform a put through GFSH I can see the CQ trigger.


Affects: 2.0 GA (Kay)

Referenced from: commits https://github.com/spring-projects/spring-data-geode/commit/a46f1cc40072435bd520c06eee55525a61ec0841, https://github.com/spring-projects/spring-data-geode/commit/d98c4afa7938e2af52e8db4872262a999eab68f7

Backported to: 2.0.1 (Kay SR1)

spring-projects-issues commented 6 years ago

John Blum commented

I think in this case, triggering of the CQ(s) from Spring Cache annotated service methods may have been all or nothing. Meaning, if a @CacheEvict annotated service method caused a CQ to be triggered, then it is likely the @Cacheable and @CachePut annotations would also cause the same CQ to be triggered.

However, there did exist 2 bugs in the code that would potentially cause a CQ to not be registered properly.

  1. The first bug involved identifying and registering CQs before the initialization of the underlying ContinuousQueryListenerContainer relative to the beans that contain @ContinuousQuery annotated callback methods (CQs). This code path leads to adding a listener to the container for the CQ callback, which creates the CQ and stores a reference for execution later, which is after the container has been initialized. However, the container will go onto clear/close all existing CQs during initialization, prior to execution. This results in having no CQs to execute.

  2. The second bug identified involves declaring a CQ (using the @ContinuousQuery annotation) on the same bean that may also be proxied by Spring for other purposes (e.g. Caching, Security or even Transaction Management). Here is 1 example where a CQ is declared on a bean that will also be proxied for caching purposes (given the presence of the Spring Caching Annotations, e.g. @Cacheable). In this case, the CQ cannot be identified since what is passed to the Spring BeanPostProcessor used to inspect and identify CQs is a "PROXY" object and not the actual bean instance declared and registered with the container. As such, the CQ never gets registered and therefore will never be triggered