Virtual Happy Hour this month, Jun 28, we'll be getting a sneak preview at our soon to launch SaaS CMS!

Try our conversational search powered by Generative AI!

Add cache master key for pricing updates


I'm trying to use a caching layer for a product listing page that depends on product updates, inventory updates and price updates. For product updates, I can use the master key EP:ECF:Version:?: and for inventory updates I can use the master key EP:ECF:IS:ALL, but for price updates there is no master key to depend on.

PriceServiceDatabase.RemoveFromCache(HashSet<CatalogKey> catalogKeySet) should not only remove cache for specific entries, but also for a master key - like you do in CatalogContentVersionStore.ClearCacheInternal(...) and InventoryServiceCacheBase.Invalidate(...).

Also, I really want you to expose these master keys as public strings. There should be no need for us developers to spend time decompiling the source to find what private strings you're using.

Nov 23, 2022 11:11

If you absolutely have to, you can use master key EP:CatalogKeyPricesMasterCacheKey

Nov 23, 2022 11:58

@Quan, that master key is not invalidated in PriceServiceDatabase.RemoveFromCache(...).

Also, I don't understand what you mean by "if you absolutely have to". To make myself clear, I'm not asking you to use the master key in your own caching - only in your own cache invalidation. By doing so, you leave it up to me to use that master key in the way I deem fit.

Edited, Nov 23, 2022 12:05

There seems to be a little misunderstanding, either by me or you. RemoveFromCache should remove cache for specific price, not remove everything. Not quite sure why you need that, but you can see ClearCacheInternal has little meaning (Clear <> Remove).

If you want to clear the entire price cache, you can do so. But we prefer the selective approach.

Nov 23, 2022 12:24

As you can see in InventoryServiceCacheBase.Invalidate(...) - the cache removes the key InventoryServiceCacheBase._allInventoryKey ( = EP:ECF:IS:ALL ). However, this key is never used by you (Episerver) when inserting into the cache. So, it's never used by yourselves to control cache but rather as a way for us consumers to act on whenever you invalidate based on that key.

Nov 23, 2022 12:53

_allInventoryKey is actually used for List() function (which in honesty I think was a bad design). When you change an inventory, the list (which contains all inventory) needs to be invalidated also. It's not the "entire inventory cache key". 

I think the intention is all Clear cache methods should be internal/hidden. You trust the framework to manage cache properly - you can depend your cache item on certain keys that are exposed, but you should not clear the cache unless you absolutely have to. 

Nov 23, 2022 12:59

Please point me to the place where _allInventoryKey is used, because I can't see it used in any List-method.

What about MasterCacheKeys.RootKey?

As you can imagine, our product listing pages with filtering and sorting does not use the content loader to provide hundreds of products. Thus, your argument about relying on the framework is simply not valid - which probably goes for lots of your customers. Your argument is only valid if the data source is something that Episerver also provide, which rules out any custom Entity Framework database, any Elasticsearch index or any other search engine. 

Edited, Nov 23, 2022 13:26

I'm not sure I get your argument. Within a subsystem like price, you trust the framework to handle the cache. If you have dependencies on certain price cache - for example if you would like your cached product listing to be invalidated when prices change, you have a few keys to use. However, clearing cache (in this context, cache of a subsystem) is generally a bad idea.

Nov 23, 2022 13:52

Assume that a product page controller creates a view model, and that this view model is composed from product data, inventory and prices. The entire view model is cached to ensure performance.

  1. Some user accesses the product page
  2. The controller makes use of IObjectInstanceCache.ReadThrough(...) to see if that view model is already in the cache, ready to be used.
  3. Some admin changes prices for the same product via the admin interface ( = there's no way for me as a developer to intercept this).

At this point, I want the cached view model to be released/cleared, don't you think? Maybe I can fix this very simple scenario, because it's just ONE product. Now imagine an entire product list with hundreds of products. Do you understand how the specific keys can be impossible to maintain? This is where the master cache keys comes into play.

Edited, Nov 23, 2022 14:09

caching a list is always tricky. However your specific example does not demand why the price (or inventory) subsystem should clear the cache every time. that would be hugely inefficient.

the way cms cache the content list, and many smaller parts of commerce do, is to cache per item. once you get the list (of ids), you try to load each of them from cache, if yes, add to your list, if not, save the id for batch load from database (or whatever data source), and also cache those.

you can depend each of your item on a specific price/inventory cache item.

that way you can reuse a lot of smaller cache entry instead of a huge one. 

Nov 23, 2022 14:21

"However your specific example does not demand why the price (or inventory) subsystem should clear the cache every time".

As I wrote earlier, the system clears only my cache - not Optimizelys cache. 

"that would be hugely inefficient."

You don't know this. I know that the data only updates so often, so I can choose to be lazy and drop my product listing cache whenever any inventory update occurs. 

"you can depend each of your item on a specific price/inventory cache item."

Actually not. In the product listing page example, with for example Elasticsearch data source, the cache key is the query itself. I do not know what items will be included in the result. That means that a product that's not part of the result the first time, will not end up as a cache dependency. If this product actually changes in a way that it should show in the results, this will not be feasible using your argument.

I literally don't understand why you are so reluctant to grasp that this is a circumstance for my customer (extremely likely for many others as well). The change that I seek would not affect your system in any way. It solely provides a way for developers to build own caching solutions in a more easy and maintainable way.

Edited, Nov 23, 2022 14:51

Quan, did you ever understand what I was asking for? Two simple lines of code at your end:

public const string PricingMasterKey = "SOME:MASTER:KEY"; // <- this one
private void RemoveFromCache(HashSet<CatalogKey> catalogKeySet)
  _objectInstanceCache.Remove(PricingMasterKey); // <- and this one

By providing this, you simply provide a way for developers to act on pricing cache invalidation. While you're at it, imo all cache key generators should be made public so that I don't have to decompile and use magic strings. Master keys and public key generators should be available for all types of entities.

Remember, you're not forcing anyone to use them. However, you do provide means for developers to build efficient caching solutions. I can't see any negative impact from your point of view - only positives.

Dec 20, 2022 10:00
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.