cachingmulemulesoftmule4mule-esb

Mule 4 Object store and caching - store records from Db in cache and then Validate incoming request against them from cache - seems it is possible


So thanks to @harshank and to @aled for helping me in my previous questions here and here

So this was something that I was not able to get working but my colleague did and to me it just does not make sense .

So here goes : Will paste the entire code below - but will start with images of the flow to better explain : This is a simple HTTP listener which is receiving incoming request : HTTP Listener

then contol goes to a subflow called caching_experiment_04 cachig implementation here

This is the actual subflow caching_experiment_04

So the way this is working is am making a post request via postman :

 {
"empId": "E001",
"isActive": true
}

#1 store original payload Here whatever is the incoming payload is being stored against a variable originalPayload

#2 send hard coded dummy payload to cache Here we are literally replacing the incoming payload with hard coded dummy payload ( The way I look at it is it is like a hack to trcik / fool the cache )

%dw 2.0
output application/java
---
{"dummy": "dummyValue"}

#3 Cache When code reaches this point - the first time nothing is present inside the cache so it 'enters' cache scope . Here in simulate db retrieval as the name states we are simulating a database call to retrieve data and store in cache . The second time around as we are passing the dummay payload to cache - I am assuming cache finds the same payload and does NOT 'enter cache scope' ( For now I am hardcoding values as :

%dw 2.0
output application/json
---
[
{
    "empId": "E001",
    "isActive": true
},
{
    "empId": "E002",
    "isActive": false
}
]

So at this stage the above data is populated in cache .

#4 Now when control reaches this point : check if incoming request is valid I can see in debug mode that the payload is actually the data that is in cache i.e the mocked array of two records from db .

Here am doing a simple business validation ( for illustration purposes only its a simple check for a specific employee id and if active

Questions: So in this hacky way ( sending dummy payload to cache everytime ) have been able to use Mule 4 Cache with object store to do an authorisation check . I am still a little unsure why when we make a second request and when code does not enter cache scope ( assuming since it finds the dummy payload in cache ) then why AFTER cache scope the payload does NOT show the dummy payload rather it shows the payload from the db simulated transform component INSIDE the cache. So I am not able to understand if incoming dummy payload is being used to determine if cache scope should be entered or not why is the incoming payload NOT being stored in cache ? and if the incoming dummy payload is NOT stored in cache why is the second request ( with same dummy payload NOT entering cache ?

NOTE : After On cache expiry and/or TTL any incoming request will enter inside cache scope and data retrieval will be triggered to refresh cache Prior to On cache expiry and /or TTL any incoming request will simply 'bounce' off the cache ( for lack of a better word )

Here is the complete code:

<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="f1bec56d-de65-4a93-913d-07a7426d6bf6" >
    <http:listener-connection host="0.0.0.0" port="9091" />
</http:listener-config>

<flow name="caching_experiments" doc:id="1846324d-ea09-4f56-8822-3a4f5f05b123" >
    <http:listener doc:name="Listener" doc:id="f1d01332-79c0-4a26-bd1c-1c9639d12168" path="/caching/*" config-ref="HTTP_Listener_config" />
    <flow-ref doc:name="caching_experiment_04" doc:id="554cb615-23ca-4f54-869b-622122910bac" name="caching_experiment_04"/>
</flow>


    <?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:os="http://www.mulesoft.org/schema/mule/os" xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core"
    xmlns="http://www.mulesoft.org/schema/mule/core"
    xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd
http://www.mulesoft.org/schema/mule/os http://www.mulesoft.org/schema/mule/os/current/mule-os.xsd">
<ee:object-store-caching-strategy name="Caching_Strategy_04" doc:name="Caching Strategy" 
    doc:id="64214a61-24bc-4231-80b3-b8e11911449d" objectStore="Object_store_04">
    </ee:object-store-caching-strategy>
    
    <os:object-store name="Object_store_04" doc:name="Object store" doc:id="cae89912-c583-4061-b684-78def42a1ada" 
    entryTtl="60" persistent="false" expirationInterval="2"/>
    
    <sub-flow name="caching_experiment_04" doc:id="593c0631-72e7-4692-bee1-5ba4cc1e0363" >
        <logger level="INFO" doc:name='"Before cache"' doc:id="83348424-a544-4df6-b0dc-4c2443187998" message="Before cache"/>
        <ee:transform doc:name="store original payload" doc:id="54674867-5302-4511-907c-139598cf8f4d" >
            <ee:message >
            </ee:message>
            <ee:variables >
                <ee:set-variable variableName="originalPayload" ><![CDATA[%dw 2.0
output application/java
---
payload]]></ee:set-variable>
            </ee:variables>
        </ee:transform>
        <ee:transform doc:name="send hard coded dummy payload to cache" doc:id="ee36fa6a-d4d9-4b53-b041-36c7cc41775d" >
            <ee:message >
                <ee:set-payload ><![CDATA[%dw 2.0
output application/java
---
{"dummy": "dummyValue"}]]></ee:set-payload>
            </ee:message>
        </ee:transform>
        <ee:cache doc:name="Cache" doc:id="80ea19f7-ca97-4409-a038-34f0c680582b" cachingStrategy-ref="Caching_Strategy_04">
                <logger level="INFO" doc:name='call db and retrieve data to be cached' doc:id="5c0815fa-29d3-4657-b74e-bc392e46b9d9" message="call db and retrieve data to be cached" />
            <ee:transform doc:name="simulate db retrieval" doc:id="066794e1-4658-41bd-9024-f3e15c145ad4" >
                <ee:message >
                    <ee:set-payload ><![CDATA[%dw 2.0
output application/json
---
[
{
    "empId": "E001",
    "isActive": true
},
{
    "empId": "E002",
    "isActive": false
}
]]]></ee:set-payload>
                </ee:message>
            </ee:transform>
            </ee:cache>
        <ee:transform doc:name="check if incoming request is valid" doc:id="e1518ccb-87bb-4c4f-ae8d-ff888b0f8dbd" >
            <ee:message >
                <ee:set-payload ><![CDATA[%dw 2.0
output application/java
---
!isEmpty(payload filter ((item, index) -> item.empId == vars.originalPayload.empId and item.isActive))]]></ee:set-payload>
            </ee:message>
            <ee:variables >
                <ee:set-variable variableName="isValid" ><![CDATA[%dw 2.0
output application/json
---
!isEmpty(payload filter ((item, index) -> item.empId == vars.originalPayload.empId and item.isActive))]]></ee:set-variable>
            </ee:variables>
        </ee:transform>
        <logger level="INFO" doc:name='"After cache"' doc:id="4f70c595-8332-494f-b0af-71517a83e346" message='#["After cache " ++ vars.isValid]'/>
    </sub-flow>
</mule>

Solution

  • The Cache Scope doesn't cache the payload that it receives but the payload that it generates when it executes the Mule Components inside the scope. When there is a match between the key of the incoming message and a cached key, it outputs the cached message information and does not execute its Mule Components. The scope always executes, it just decides when it needs to execute the contained components. Since it is using the cache you can only confirm the execution by the replacement of the payload.

    Note that because you are not defining a key generation expression, it is using the default which is a SHA256 digest of the input payload. Since you are just using a fixed dummy payload this is not probably an issue, but you should be mindful of it in other scenarios.