Apigee caching Key Value Map entries for longer than expected

I have a value in a KVM which I am using to store the rate limit for a Spike Arrest.

In my proxy, I have a KVM Operations Policy to retrieve it:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<KeyValueMapOperations async="false" continueOnError="false" enabled="true" name="KV-GetSpikeArrestLimitValue" mapIdentifier="SpikeArrest">
    <DisplayName>GetSpikeArrestLimitValue</DisplayName>
    <Properties/>
    <ExclusiveCache>false</ExclusiveCache>
    <ExpiryTimeInSecs>10</ExpiryTimeInSecs>
    <Get assignTo="spikeArrestValue">
        <Key>
            <Parameter>SpikeArrestValue</Parameter>
        </Key>
    </Get>
    <Scope>environment</Scope>
</KeyValueMapOperations>

When I am changing the KVM value, the execution of this policy doesn't seem to pick up the change. My understanding of the ExpiryTimeInSecs parameter is that it should refresh after 10 seconds, but this isn't the case. Even deleting the KVM doesn't help; the old value is still referenced.

4202-kvmissue.png

The KVM concept loses it's value in this Use Case if we can't replicate updates relatively quickly. The danger is that we knock the value down low during a difficult period, then knock it back up again, but we have no control over when the value is replicated into cache.

Am I missing something?

Solved Solved
1 8 1,044
1 ACCEPTED SOLUTION

John - to answer your question, yes, you are missing something!

The behavior you are seeing is confusing but there is a simple explanation.

You had a prior version KVM-Get policy that specified an ExpiryTimeInSecs of something more than "Several hours". Maybe you used 86400, maybe something larger. When you ran the KVM-Get the first time, it populated the cache with the TTL of 86400 (or whatever you used).

The TTL of 86400 is often the used because at one point, that value was used in the same policy configuration in our documentation!

Then, you modified the KVM-Get policy to specify 10 seconds for ExpiryTimeInSecs. You re-ran the KVM-Get expecting to see the data being cached for only 10 seconds. But that expectation is wrong.

The cache would be kept for only 10 seconds IF the cache were not already populated. But the element you are trying to read is already in cache, and that cached element has an expiry (aka TTL), which you cannot change, or even see. So a KVM-Get continues to return what you consider to be "stale" data.

To escape this situation, you have some options.

  • Change the key. Use anything different from SpikeArrestValue. Use "Tomato". Be sure to insert an item into your KVM with that new key. This key will not have been cached. The first time it is cached it will use the value you specified in the ExpiryTimeInSecs element at the time the policy executed. (In your case, 10 seconds)
  • Run a KVM-Put on the same key ("SpikeArrestValue"), specifying a value of "30ps" and an ExpiryTimeInSecs element of 1. This will write the value to the KVM, and also write the value to the cache, overwriting the existing cached item and its mystery TTL. You need to do this only once. You can attach this policy to a flow that is used only temporarily, or to your existing flow. After you invoke this policy once, you can remove it. Updating the KVM this way, via policy, updates the runtime cache in the message processor. Updating the KVM via the Administrative UI or API will not flush the runtime cache in the message processor. After you run the KVM-Put just once, you can remove the policy from your proxy. Or, leave it in the proxy, protected by appropriate authorization check, to allow for future reset of the cache.

Either way will lead you to joy.

View solution in original post

8 REPLIES 8

Hi @John Ferguson - This should ideally not happen. I tried the same code you have and it works as expected. I have my trace ON - I can see 30ps coming from KVM. While the trace is still ON, I updated the KVM value to 50ps and hit the proxy to get the new 50ps.

Can you confirm if you are changing the value of the KVM entry in the correct environment ? Its also possible that you are updating the entries in the wrong environment. I have done a few times in a hurry :0

Hello @Sai Saran Vaidyanathan.

Just to be absolutely sure I went back and checked. I'm definitely updating in the same environment.

Thanks for confirming @John Ferguson. Is this on Cloud ? Can you share your and proxy info by using the Ask the Expert option on the right

John - to answer your question, yes, you are missing something!

The behavior you are seeing is confusing but there is a simple explanation.

You had a prior version KVM-Get policy that specified an ExpiryTimeInSecs of something more than "Several hours". Maybe you used 86400, maybe something larger. When you ran the KVM-Get the first time, it populated the cache with the TTL of 86400 (or whatever you used).

The TTL of 86400 is often the used because at one point, that value was used in the same policy configuration in our documentation!

Then, you modified the KVM-Get policy to specify 10 seconds for ExpiryTimeInSecs. You re-ran the KVM-Get expecting to see the data being cached for only 10 seconds. But that expectation is wrong.

The cache would be kept for only 10 seconds IF the cache were not already populated. But the element you are trying to read is already in cache, and that cached element has an expiry (aka TTL), which you cannot change, or even see. So a KVM-Get continues to return what you consider to be "stale" data.

To escape this situation, you have some options.

  • Change the key. Use anything different from SpikeArrestValue. Use "Tomato". Be sure to insert an item into your KVM with that new key. This key will not have been cached. The first time it is cached it will use the value you specified in the ExpiryTimeInSecs element at the time the policy executed. (In your case, 10 seconds)
  • Run a KVM-Put on the same key ("SpikeArrestValue"), specifying a value of "30ps" and an ExpiryTimeInSecs element of 1. This will write the value to the KVM, and also write the value to the cache, overwriting the existing cached item and its mystery TTL. You need to do this only once. You can attach this policy to a flow that is used only temporarily, or to your existing flow. After you invoke this policy once, you can remove it. Updating the KVM this way, via policy, updates the runtime cache in the message processor. Updating the KVM via the Administrative UI or API will not flush the runtime cache in the message processor. After you run the KVM-Put just once, you can remove the policy from your proxy. Or, leave it in the proxy, protected by appropriate authorization check, to allow for future reset of the cache.

Either way will lead you to joy.

I followed your first option and that seems to have done the trick. We're at a stage of development where the KVM name is not locked in stone, so we can just do this.

I only ever add KVM values from the Edge UI and I don't remember setting a long expiry date in any of the KVMO policies, but it's possible me or one of my devs did it during a sandboxing exercise without realising. Something to be mindful of though.

Many thanks.

There always has scenario to make an urgent changes on KVM and it must be effect upon submission.

Ideally, apigee should invalidate the cache if an entry of KVM is changed.

Option 2 in my post does exactly this.

Another option is not to use the caching built into the KeyValueMapOperations but to use the Apigee Caching policies themselves. This gives you much more control without renaming and things like that.

There is a detailed example here: https://community.apigee.com/articles/24906/a-pattern-for-caching-kvm-values.html