Caching in Mule 4

Suman Chatterjee
Another Integration Blog
8 min readJun 30, 2023

You work on a requirement, which tries to fetch data from a data source (say every 5 mins). This data source could be a database for an example.

Now since we all know that a call to any database is resource intensive, and if we are doing just a fetch, repetitively, we are consuming a lot of system and network resources. More over if there are chances that for two or three consecutive fetches, one may get the exact result set as the response from the database, this is just a waste of resources. However since you cannot question the requirement, and need to call, how about some performance and design enhancements.

In such scenarios, it would be very handy if the result set retrieved from the database can be stored somewhere, and can be reused ( within acceptable time limit).

The process of storing some data so that it can be reused (within acceptable time limit) is nothing but caching

Now a bigger question is where do you store the data? Do you again store the data in another Database? Naah.. that will be a very poor design.

Generally such type of data is saved “IN MEMORY”, and it is either wiped out or replenished with a new set of data once the acceptable time limit expires.

Apart from storing the data in the memory, the same can be stored in Object Stores as well as in REDIS (REmote DIrectory Server) and other storages. You can also do caching at the network level via proxies. These are typically done using CDN (Content Delivery Networks) . There are other ways also that caching can be done like the DNS Caching which is done at the Operating System Level. The data that is getting cached can be stored any where that you want like a Database, file system, memory, or even any external storages. The only caveat is that the data should be retrievable very quickly and easily. Hence the In Memory Caching is the most popular type of caching the folks generally use.

Different Types of Caching

Let’s see a few ways how we can implement caching strategies in MuleSoft

  1. Using Object Stores/Redis
  2. Using Cache Scope
  3. Using HTTP Caching as API Proxy

Caching Using Object Stores / Redis :

This is one of the most basic ways we use, to implement caching.

Typical Caching Using Object Stores

Here a MuleSoft API tries to retrieve a token from Dynamo DB which does is updated every 4 hours. This token is used for further processing and making calls to other APIs (outside the scope of this blog).

A. For the first time, the API directly calls the Dynamo DB to retrieve the token (1 & 2 ).

B. During this call, the token that is retrieved from the Dynamo DB is also stored in the Object Store ( 3 & 4 ). The MuleSoft API does further processing and then the resultant data is sent to the backend mainframes (5).

C. Now if the MuleSoft api needs to use the token once again, it will want to make a call to the Dynamo DB once again. However it first checks the whether there is any token that is available in the object store and when was the last time it was updated (1 & 6 ). If the data was updated, less than 4 hours ago, the token is retrieved from the the Object Store. Else the mule API would make another call to the Dynamo DB to get the new token and update the object store.

D. Also for better Cache Handling ( 7 ), there is a separate mechanism which clears the cached token exactly 4 hours it is updated. This way, even by mistake an old or stale token will not get used by the mule API.

Now there is one major issue with this design. This will work very nicely if the organization is using CloudHub. However if the organization is using Run Time Fabric (RTF) then with every restart of the POD, the cache will seize to exist. In RTF the Object Stores are supported but with caveats. For more details https://help.mulesoft.com/s/article/Object-Store-Feature-Support-in-MuleSoft-Runtime-Fabric

In such scenarios, the design still remains the same (ALMOST). Here the Object Store gets replaced by the REDIS for better data durability

There isn’t any major implementation change other than the caching tool. The processing and the logic still remains the same.

Caching Using Cache Scope:

The second way we can work with caching in mule is using the cache scope. If you see the following work flow diagram, we have a flow which is having a cache scope within it. Now when the request comes in, the first thing that is checked is if the payload is consumable/non-repeatable stream.

Cache Scope flow diagram
Cache Scope Flow Diagram

If the payload is a non repeatable stream (or consumable), the caching WILL NOT WORK. while processing the incoming message, it would clearly call it out in the logs

HTTP Listener configured for non-repeatable stream
Logs calling out the payload is consumable.

Once the consumable payload check is complete, the mule runtime, creates a KEY. Once this is done, it checks the cache store to check if the cache has any existing value for the key that has been generated. If the key is not found, then it is called a CACHE MISS. In such cases, the flow will enter the cache block and then calls the http request and does the necessary processing. Now before sending the final response, it stores this in the cache store against the key that was earlier generated as its value. This will be used in the future. And finally the final response is sent out.

In the scenario that the key that was generated, matches one of the existing keys in the cache store, that is called a CACHE HIT. In such situations, the processing does not go into the cache scope anymore, but the existing cached data from the store is sent as a response. There is a small caveat to this. The cached data will be sent out till the time the TTL of the data is not expired or the data is not invalidated. In those scenarios, the data will be again fetched from the http requestor just as it works if there is a cache miss.

Let’s look at the logs when the cache scope works.

If you see the logs. the first time, the processing enters the cache scope, calls the http requestor and logs accordingly.

However the subsequent request does not enter the cache scope at all. The response is sent out from the cache that is stored.

Now let us see what are the different types of caching stores that are available for us to use. From the diagram, we have the default store, the Object Stores and the External Stores.

While working on applications that are deployed on the CloudHub, we can use the all the three options which is the default, object store as well as the external caches. Now the default version of the storing is either an In-Memory cache or Persistent Cache. Persistent Cache saves the data in the disk/file system of the node. The In-Memory option is a volatile one and will be removed each time a worker node is restarted. This option should always be avoided when the data needs to persist and shared across multiple workers. In those scenarios, we use either the Object Store V2 or an external Cache service.

While working with applications, which are deployed On-Premise, the Object Store V2 is not available. However the mule object store is still available. The caveat is that this is an in memory object store stored in the heap of the worker and every restart will clear the cache.

While we are discussing about caching, it is important to note that we always cache responses of IDEMPOTENT Calls.

Caching Using HTTP Caching Policy in API Manager:

This is the third way that we can use caching. This is a very easy way of implementing Caching in our applications. This policy enable the reuse of the HTTP responses sent out previously thus speeding up the average response time of the API without having to hit the backend service, if not required.

While implementing this Proxy ruleset, there are a few things that needs to be kept in mind.

HTTP Caching Key: This key will be used to check the incoming request and its corresponding key value pair in the cache store.

Maximum Cache Entries: The number of entries that will be stored in the cache.

Entry Time to Live: How long the cached data is reused, before the actual backend implementation is called to replenish the cache for reuse.

Distributed: This flag has to be enabled if are working with clusters or having multi worker deployments.

Persistent: This flag is enabled if the Cache needs to persisted in case the data needs to persist, should there be a runtime restart.

Follow HTTP Caching directives :to add proper HTTP headers in response to tell client we are using caching
Invalidation Header: To specify in case we don’t want cache result
Condition Request Caching Expression: Based on which caching will be used so if condition is true then only use caching e.g. storing the result in cache and reuse in case we get the same request
Condition Response Caching Expression: Based on which caching will be used so if condition is true then only use caching e.g. storing the result in cache and reuse in case we get the same request

--

--

Suman Chatterjee
Another Integration Blog

Mulesoft Senior Architect. Writer for Another Integration Blog. MuleSoft Mentor | Meetup Leader | Meetup Speaker