Elastic Path Commerce Development

Enabling Request-Scoped Caching on a Repository Method

Enabling Request-Scoped Caching on a Repository Method

Once you have ensured that your repository is in the correct package and named correctly, you can cache method responses by annotating them with the @CacheResult annotation.
@CacheResult
public Customer getCustomer(CustomerId customerId){ ... }

In most cases, the @CacheResult annotation is the only thing needed to enable caching.

Cache Key Variants

Repository methods may need to retrieve the same domain objects by different keys, as different resources provide different information on the same object. For example, a resource which knows about a user's default cart may not know about that cart's GUID, whereas a resource accessed via a URI that retrieves a specific cart does.

If you must retrieve the same domain object with via different unique identifiers, enable cache key variants to avoid a decrease in performance.

How Cache Key Variants Work

Domain objects may have multiple key variants by which they can be retrieved. In general, any uniquely identifying field of a domain object can be used as a cache key.

Cache key variants allow the domain object to register itself with a CacheKeyManager class, tracking all possible values that useable as a cache key. This allows Cortex to identify when an object can be retrieved from the cache, even if it is called by a different key than it was initially cached under.

For example, the class Customer has two fields which can be used as unique identifiers:
class Customer {
          String storeCode, userId;
          String guid;
}

A repository class has the following cached methods, both of which retrieve the same domain object by different unique identifiers in their method signatures:

@CacheResult
public Customer findCustomerByUserId(String storeCode, String userId) { ... }
          
@CacheResult
public Customer findCustomerByGuid(String guid) { ... }

In this example, the first method, findCustomerByUserId(), caches the domain object. The second method, findCustomerByGuid(), utilizes cache key variants to retrieve the domain object cached by findCustomerByUserId(), rather than retrieving the object again from Commerce Engine.

Implementing Cache Key Variants

Cache key variants are not implemented by default. To implement cache key variants on a domain object:

  • Implement the CacheKeyVariants interface
  • Within this implementation, register the key variants of the domain object you wish to cache.
  • Register the interface implementation with the CacheKeyManager class.
Important: Key Variants Must be Unique

Key variants have to be unique otherwise inconsistencies might occur.

For example, the CustomerCacheKeyVariants class registers the key variants of the Customer domain object:
@Singleton
@Named("customerCacheKeyVariants")
public final class CustomerCacheKeyVariants implements CacheKeyVariants<Customer> {
              
  @Override
  public Collection<Object[]> get(final Customer customer) {
    return Arrays.asList(
      new Object[] { customer.getGuid() },
      new Object[] { customer.getStoreCode(), customer.getUserId() }
    );
  }
                
  @Override
  public Class<Customer> getType() {
    return Customer.class;
  }
}}

Best Practices

Avoid Method Signature Collision

Caches may have methods with the same return type and input parameters. To avoid collision, use a uniqueIdentifier with the @CacheResult annotation. The following example shows how to apply a uniqueIdentifier.
@CacheResult(uniqueIdentifier = "default-customer-address")
public Address getDefaultCustomerAddress(CustomerId customerId) { ... }
            
@CacheResult(uniqueIdentifier = "shipping-address")
public Address getShippingAddress(CustomerId customerId) { ... }

Only use CacheKeyVariants on Unique Identifiers

Using CacheKeyVariants is an essential rule for performance optimization.