svc-cache¶
Key/value cache for reference data shared across processors. Two implementations: in-memory and JSON-backed.
<dependency>
<groupId>com.telamin</groupId>
<artifactId>svc-cache</artifactId>
<version>1.0.35</version>
</dependency>
Implementations¶
| Class | Persistence | LRU |
|---|---|---|
InMemoryCache |
None | Optional via maxSize |
JsonFileCache |
JSON file on disk | Optional via maxSize |
Both implement the same Cache interface so the consuming processor is implementation-agnostic.
Sample¶
services:
- name: state-cache
serviceClass: com.telamin.mongoose.plugin.svc.cache.Cache
service: !!com.telamin.mongoose.plugin.svc.cache.JsonFileCache
fileName: ./data-out/state.json
maxSize: 10000 # 0 = unbounded
asyncWrite: false # write on every put if false
- name: hot-prices
serviceClass: com.telamin.mongoose.plugin.svc.cache.Cache
service: !!com.telamin.mongoose.plugin.svc.cache.InMemoryCache
maxSize: 5000
Registering as Cache, not the concrete impl
serviceClass: com.telamin.mongoose.plugin.svc.cache.Cache registers the
service under the interface so processors that inject @ServiceRegistered
Cache cache find it regardless of which implementation is wired. Drop in
JsonFileCache for persistence or InMemoryCache for pure in-memory —
consumers don't care.
Omit serviceClass to register under the concrete class instead.
Inject:
public class PriceMonitor extends ObjectEventHandlerNode {
private Cache prices;
@ServiceRegistered
public void useCache(Cache prices, String name) {
this.prices = prices;
}
@Override
protected boolean handleEvent(Object event) {
if (event instanceof Tick t) {
prices.put(t.symbol(), t.price());
}
return true;
}
}
LRU eviction¶
When maxSize > 0, the cache switches to access-order LinkedHashMap semantics. Each get or put marks the entry as most-recently-used. When size > maxSize, the eldest entry is evicted and evictedCount is incremented.
InMemoryCache cache = new InMemoryCache();
cache.setMaxSize(2);
cache.put("a", 1);
cache.put("b", 2);
cache.put("c", 3); // evicts "a"
cache.get("b"); // touches "b" → b is now MRU
cache.put("d", 4); // evicts "c", not "b"
cache.getEvictedCount(); // 2
For JsonFileCache, eviction also flags the file as dirty so the next doWork() (or sync put) writes the trimmed state to disk.
Configuration reference¶
InMemoryCache¶
| Field | Default | Notes |
|---|---|---|
maxSize |
0 |
0 = unbounded ConcurrentHashMap. |
JsonFileCache¶
| Field | Default | Notes |
|---|---|---|
fileName |
required | Throws IllegalStateException if unset. |
maxSize |
0 |
0 = unbounded ConcurrentHashMap. |
asyncWrite |
false |
If true, only doWork() writes to disk. |
Operational notes¶
- Parent directories are auto-created.
- Bare basenames (no
/) work — nogetParentFile()NPE. tearDown()writes the cache to disk and is safe to call without aninit().- The cache also registers admin commands
cache.<name>.keysandcache.<name>.get <key>with the admin registry — wiresvc-admin-telnet,svc-admin-rest, orsvc-admin-webto inspect cache contents at runtime. (svc-admin-webauto-renders these as a dedicated Cache panel.)
Examples¶
- plugins/service-plugin-example —
@ServiceRegisteredtemplate. - how-to/data-mapping — the natural place to wire a cache for warmed reference data.