Can't LookupCache between subsequent requests

Hi,

I'm trying to get the populate / lookup cache policies working and running into some trouble.

For reference this is my current setup:

LookupCache Policy

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LookupCache async="false" continueOnError="false" enabled="true" name="LC-STSResponse">
    <DisplayName>LC-STSResponse</DisplayName>
    <Properties/>
    <CacheKey>
        <KeyFragment>sts</KeyFragment>
        <KeyFragment>AccessKeyId</KeyFragment>
        <!--<KeyFragment ref="iam-role-arn"/>-->
    </CacheKey>
    <Scope>Proxy</Scope>
    <AssignTo>sts.AccessKeyId</AssignTo>
</LookupCache>

 

PopulateCache Policy

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="PC-STSResponse">
    <DisplayName>PC-STSResponse</DisplayName>
    <Properties/>
    <CacheKey>
        <KeyFragment>sts</KeyFragment>
        <KeyFragment>AccessKeyId</KeyFragment>
        <!--<KeyFragment ref="iam-role-arn"/>-->
    </CacheKey>
    <Scope>Proxy</Scope>
    <ExpirySettings>
        <TimeoutInSeconds>300</TimeoutInSeconds>
    </ExpirySettings>
    <Source>sts.AccessKeyId</Source>
</PopulateCache>

 

SharedFlow

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SharedFlow name="default">
    <Step>
        <Name>LC-STSResponse</Name>
    </Step>
    <Step>
        <Name>KVM-GetAWSKeys</Name>
    </Step>
    <Step>
        <Name>AM-AWSConnection</Name>
    </Step>
    <Step>
        <Name>AM-AWS-Sigv4-Request</Name>
    </Step>
    <Step>
        <Name>STS-AssumeRole</Name>
    </Step>
    <Step>
        <Name>EV-STSResponse</Name>
    </Step>
    <Step>
        <Name>PC-STSResponse</Name>
    </Step>
    <Step>
        <Name>LC-STSResponse</Name>
    </Step>
</SharedFlow>

 

Basically I can retrieve a value from my cache if I LookupCache right after I Populate cache in the same request. But when I try to LookupCache at the start of my flow it will never find a cached value.

I've tried both shared cache & environment cache, I've tried a variety of CacheKeys/Prefixes/Scopes, various TimeoutInSeconds expirations. 

When I trace it always shows cachehit=false on the first LookupCache policy I'm trying to get to retrieve my value from a previous request.

It doesn't seem to matter if I make 2 requests or 10 requests, I never see a value come back in my subsequent call.

There are a variety of similar questions here on this topic, and I think I've been through most of them, but I haven't been able to spot what I'm doing wrong from other community posts or through my own effort reading Apigee Edge documentation.

I'd really appreciate any tips someone could offer.

Thanks,

Jared

 

 

0 1 85
1 REPLY 1

It seems like it should work. Hmmm.

I'll bet what you're doing is calling LookupCache from directly within the API proxy, and then PopulateCache from the SharedFlow. Right? I just tried that and reproduced what you reported. If that's the case, the problem is the cache key is being constructed differently when the LookupCache policy is referenced from a SharedFlow, as compared to being referenced from within an API proxy directly. This is a sort of unfortunate surprise due to the way sharedflows are implemented internally.

When you use Scope=Proxy in your LookupCache policy, the cache key gets calculated like this:

 

ORG__ENV__APIPROXY__PROXYENDPOINT__FRAGMENTS

 

...where each of those all uppercase things gets replaced with the name of the thing, and FRAGMENTS is replaced with the things from the policy, in your case FRAGMENTS would be sts_AccessKeyId . We say that everything before __FRAGMENTS is the "cache key prefix".

But when attached in a SharedFlow, the APIPROXY part of the cache key gets replaced by... the name of the shared flow! Surprise!

To avoid this

  • attach the LookupCache policy in the same SharedFlow that executes the PopulateCache! You can do this by parameterizing the sharedflow (example below). That way one SF can do multiple things. The PopulateCache and the LookupCache will use the same cache key.
  • Specify a CacheKey Prefix in the policy configuration. This effectively supercedes the calculation of the cache key prefix when you use a scope. If you use both Scope and Prefix, Prefix takes precedence.

The description of how the Prefix and Scope works... is documented!  But I concede that it's a little complicated and the "wrinkle" of using the Sharedflow name instead of the API proxy name is confounding.

To help diagnose this cachekey calculation, you can examine the "FlowInfo" for the cache policy - it will show you the calculated cache key. It looks like this in the debug window:

debugsession.png

You can also read the context variable "lookupcache.POLICYNAME.cachekey" to get that value within your API proxy flow, where POLICYNAME is the name of the LookupCache policy. I

You can use a combination of these things. In other words you can use the Prefix property in the LookupCache policy in your proxy. That would allow it to access the item that you cached from within the SharedFlow. Make sure to use a fixed string, and it should be ORG_ENV_SFNAME_PROXYENDPOINT . (This assumes you use Scope=Proxy in the PopulateCache withiin the SharedFlow) .

ok now .... how do you parameterize SharedFlows? The FlowCallout accepts a parameter list. like this:

 

<FlowCallout name='FC-Lookup-Cache'>
  <Parameters>
    <Parameter name='fc-action'>just-lookup</Parameter>
  </Parameters>
  <SharedFlowBundle>cache-ops</SharedFlowBundle>
</FlowCallout>

 

Within your sharedflow, just examine the parameter value within Conditions. Like so:

 

<SharedFlow name="default">
    <Step>
      <Name>LC-Cached-Data</Name>
      <Condition>fc-action = "just-lookup"</Condition>
    </Step>
    ...

 

Unfortunately at this time there is no way to wrap a condition around a sequence of steps (outstanding feature request). So you need to repeat it for as many steps as you need, which gets somewhat verbose. But it's easy to read for a small number of "action cases" and steps.

Finally, you may be able to do what you want - call lookupcache from the same sharedflow that calls populatecache - elegantly, without any "actions". It might look like this:

 

<SharedFlow name="default">
    <Step>
      <Name>LC-Cached-Data</Name>
    </Step>

    <!-- just for diagnostics -->
    <Step>
      <Name>AM-Diagnostics-Cache-Key</Name>
    </Step>
    <Step>
      <Name>AM-Diagnostics-Cache-Miss</Name>
      <!-- this condition assumes 'cached-data' is the thing we read from cache -->
      <Condition>cached-data = null</Condition>
    </Step>
    <Step>
      <Name>AM-Diagnostics-Cache-Hit</Name>
      <Condition>NOT(cached-data = null)</Condition>
    </Step>

    <!-- if not in cache, insert an item -->
    <Step>
      <!-- get the value. Often this might be a ServiceCallout to fetch -->
      <Name>AM-Timestamp</Name>
      <Condition>cached-data = null</Condition>
    </Step>
    <Step>
      <Name>PC-Cached-Data</Name>
      <Condition>cached-data = null</Condition>
    </Step>

    <!-- read the thing we just wrote -->
    <!-- this step is necessary to fill the data value -->
    <Step>
      <Name>LC-Cached-Data</Name>
      <Condition>cached-data = null</Condition>
    </Step>

</SharedFlow>