Skip to content

Toro Cloud Dev Center


examples package: Caching

The examples package provides an example service that demonstrates how caching can be done via functions from the Cache class.

The cachingDemo.CachedWeatherResponseDemo.gloop service caches the current weather forecast provided by a mock weather service1, then deletes the entry 10 seconds after it has been created. This service has been exposed as a REST API and can be accessed through the following URL2:

1
<host>/api/cached/mock-api/getCurrentWeather/{city}/{countryCode}

Related articles

Please see the following articles for more information:

Try it!

In the Navigator, expand the examples package and navigate to the code folder, then expand the cachingDemo package. This package contains the files and/or directories as shown below:

1
2
3
4
5
6
7
8
examples
├── ...
└── code
    └── ...
    └── cachingDemo
        ├── api
        │   └── CachedMockedWeatherApi.api
        └── CachedWeatherResponseDemo.gloop

Under this package is the CachedWeatherResponseDemo.gloop service which demonstrates cache usage and the cachingDemo.api.CachedMockedWeatherApi.api file, which exposes the CachedWeatherResponseDemo.gloop service as a REST endpoint.

By running the service multiple times3 within the cache entry expiry time (10 seconds by default), the response of the service will be the same. When the cache entry expires, it will respond with a new set of data and will be returning that same data for that same specific amount of time again.

The service will also log messages showing whether the cache was used or not. When the cache doesn't have the entry the service is looking for, it will log a message similar to the following:

1
2
INFO  [Martini] No cache entry found. Creating a cache entry...
INFO  [Martini] The generated mock weather forecast below is now saved in the cache, this service will keep on returning this value until the cache expires (10 seconds from when it was saved. See line 6 of this service)

If you keep executing the service within the configured expiry time of seeing the previous message, it will log the following:

1
[Martini] Found a cache entry! Returning a cache entry...

After the cache entry has expired, the first log messages will appear again, showing that the cache has removed the entry (as configured).

See comments for documentation

You will find a more detailed explanation about this example you if check the Comments tab (found within the Properties view) of CachedWeatherResponseDemo.gloop. Each step in the service is also decorated with comments4 to better explain the implementation.

Explanation

Each Martini package contains its own CacheManager. The examples package has one already set up and its configuration is defined in conf/caches.conf.

1
2
3
4
5
6
examples
├── ...
├── code
└── conf
    ├── caches.conf
    └── ...

Inside the caches.conf file, there is a CacheManager configured called cachedWeatherResponse that's used to cache the response from the exposed REST API.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
cachedWeatherResponse {
    provider = "guava"  // (required)
    // Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed
    // after the entry's creation, or the most recent replacement of its value.
    expireAfterWrite = 10s  // (optional) <long>ns | us | ms | s | m | h | d default is ms

    // Each entry should be automatically removed from the cache once a fixed duration has elapsed
    // after the entry's last access time, the most recent replacement of its value, or its last access.
    //expireAfterAccess = 5s  // (optional) <long>ns | us | ms | s | m | h | d default is ms
}

If you want to set up your own CacheManager, simply create a caches.conf file for your package and define your CacheManager there. You can define multiple CacheManagers in the caches.conf file. Once configured, restart the package for the caches to be configured and started.

Martini currently supports Ehcache, Guava, and Redis. Below is a sample configuration you can use to set up your own CacheManager:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
myCache1 {
     provider = "guava" // Required
     expireAfterWrite = 1h
     expireAfterAccess = 15m

     heap = 3200
 }
 myCache2 {
    provider = "ehcache" // Required
    expireAfterWrite = 1h
    expireAfterAccess = 15m

    key {
       type = "java.lang.String" // Required
       serializer = ""
    }

    value {
       type = "java.io.Serializable" // Default
       serializer = ""
    }

    heap = 3200 // 3200 entries; may append units (e.g. MB)
    offHeap = 5MB
    disk = 10MB
    diskStore = /tmp/ehcache // Required if using disk persistence
}
 myCache3 {
    provider = "redis" // Required
    connectionName = "myRedisConnection" // Redis connection name to use

    expireAfterWrite = 1h
    expireAfterAccess = 15m
    asyncWrites = false // Whether to write to Redis asynchronously or not

    // Optional custom io.lettuce.core.codec.RedisCodec to use to encode and decode keys and values for the cache
    codecClassName = "com.company.MyRedisCodec" 

}

The format above uses HOCON - a superset of JSON. At minimum, a cache is configurable with just:

1
2
3
4
5
6
cacheName {
    provider = guava | ehcache | redis
    heap = `long`

    expireAfter* =             // if not provided, the cache entries won't expire
}

  1. based on a city-country combination 

  2. <host> must be substituted with the base URL of your Martini instance. This URL will depend on the where your instance is hosted and how you've configured your server. 

  3. You can do this easily via REST API calls to /cached/mock-api/getCurrentWeather/{city}/{country}

  4. Open the service file to see comments. Make sure comments are also not hidden.