Caching
Use SDK cache abstractions for thread-safe reference data and temporary workflow state.
SDK caches provide thread-safe storage for reference data, expensive FHIR or external lookups, message deduplication, and temporary workflow correlation.
Initialize caches in onStartup() whenever possible. Caches created there are reused by subsequent hook invocations within the same script generation.
Caches are intended for temporary/reference state. They are not durable persistence and should not be used as a replacement for FireSonic message persistence.
Cache types
| Type | Best for | Important behavior |
|---|---|---|
ExpiringCache<K,V> | Many temporary values such as recent message IDs or lookup results. | TTL-based entries; use a bounded maxSize when key count can grow. |
SingletonExpiringCache<T> | One temporary value such as the last Encounter. | No loader; set the value explicitly. |
RefreshingValueCache<T> | Reference data loaded from FHIR or an external system. | Reloads periodically through a loader while following runtime refresh/retention behavior. |
TTL key-value cache
A TTL cache is useful for deduplication and bounded lookup results. This example remembers recently seen HL7 Message Control IDs.
ExpiringCache<String, Boolean> recentMsgIds
@Override
void onStartup() {
recentMsgIds = caches.createTtlCache(
"recentMsgIds",
Duration.ofMinutes(30),
10000
)
}
FilterResult shouldProcess(MessageEnvelope envelope) {
String key = envelope.messageControlId
if (key && recentMsgIds.getIfPresent(key)) {
return FilterResult.reject(
"Duplicate messageControlId: " + key
)
}
if (key) recentMsgIds.put(key, true)
return FilterResult.accept()
}
Singleton TTL cache
Use a singleton cache when the script needs one temporary value rather than a key/value collection.
SingletonExpiringCache<Encounter> lastEncounter
@Override
void onStartup() {
lastEncounter = caches.createSingletonTtlCache(
"lastEncounter",
Duration.ofHours(1)
)
}
void rememberEncounter(Encounter encounter) {
lastEncounter.set(encounter)
}
Refreshing cache
A refreshing cache is suited to reference data that should be periodically reloaded from FHIR or another external system.
def locations
@Override
void onStartup() {
locations = caches.createRefreshingCache(
"locations",
Duration.ofMinutes(5),
Duration.ofHours(1),
{ loadLocationsFromFhir() }
)
}
def loadLocationsFromFhir() {
return fhir.search(
"Location",
["status": "active"]
)
}
List getCurrentLocations() {
return locations.get()
}
Usage guidance
- Prefer SDK cache abstractions over custom static maps or mutable shared collections.
- Create shared caches during
onStartup()rather than inside per-message hooks. - Choose TTLs according to how quickly the source data can become stale.
- Bound multi-key caches with an appropriate maximum size.
- Do not store durable business state only in an in-memory cache.
SDK cache abstractions are thread-safe and are intended to be shared across concurrent hook executions.
