Annotation Cache
Purpose
Annotation Cache makes successfully added annotations immediately available to Sonicweb, publishing them to RabbitMQ for eventual persistence into Accumulo. It also supports sharing annotations across regions and reduces repeated Datawave lookups.
This is a transient cache and messaging bridge, not the system of record. Downstream persistence into Accumulo and RabbitMQ federation are deployed separately.
Architecture
- Sonicweb reads and writes through Hazelcast using
HazelcastAnnotationRepository. It owns Datawave lookups, result merging, per-user visibility checks, and cache-hit auditing. The cache service does not query Datawave or enforce per-user visibility. serviceruns Hazelcast members. AnnotationCacheConfiguration defines two fixed shared maps: annotations and authorization-specific source-lookup markers. Fixed maps avoid creating a map per document.apiprovides the shared map contract, annotation keys, and fetch keys. Both members and clients must depend on a compatible API.- RabbitMQ receives local write-through annotations through AnnotationMapStore; source results cached by Sonicweb are cache-only and are not published. LoadCacheConsumer caches remote annotations without republishing them, preventing federation loops. Duplicate deliveries preserve existing entries; annotation IDs are assumed to identify immutable annotations, not revisions.
Design boundaries
Availability and persistence
For local write-through annotations, AnnotationMapStore requires confirmed RabbitMQ acceptance or fails the map write. RabbitTopologyConfig declares the durable annotation topic exchange and durable annotation.cache queue with a # binding. The topology survives broker restarts; retaining messages also requires persistent delivery.
The guarantee ends at RabbitMQ acceptance. This service defines no guarantees for downstream processing or persistence into Accumulo. A confirmation timeout fails the write without cancelling publication: RabbitMQ may already have accepted the message or accept it later. Retrying may publish duplicates; downstream consumers must handle them. Hazelcast writes and RabbitMQ publication are not an atomic transaction.
Choose annotation retention to cover expected Accumulo persistence and federation lag. An annotation that expires before Datawave can return it may temporarily disappear from reads. Cache retention cannot substitute for reliable persistence into Accumulo.
Cache clears do not delete annotations persisted in Accumulo, and concurrent writes can repopulate cleared entries.
Freshness, not completeness
A fetch marker means a recent successful Datawave lookup for an authorization context, not a complete annotation snapshot. Annotations are shared across authorization contexts; markers do not replace per-user visibility checks. Sonicweb caches successful empty results too. Existing cached annotation IDs take precedence when source results are merged.
Marker expiry causes another source lookup on the next request; there is no background refresh, and cache hits do not renew freshness. Marker identity uses the proxy chain's common authorizations, not sonicQueryParams; changing query parameters alone does not force a lookup.
AnnotationSyncListener and AnnotationCacheTopologyListener invalidate markers when annotation data may have been lost. Invalidation is asynchronous and best-effort; marker TTL bounds missed invalidations, and clears are not barriers against concurrent requests.
Disabling Sonicweb result caching forces source lookups and ignores cache-only results, but preserves cached write-through annotations and their persistence path.
Compatibility
Members and clients must use compatible Hazelcast and Java serialization settings. The key serialization proxies and tuple encoding are a wire contract; do not replace them with custom key serializers. Incompatible contract changes require coordinated deployment and rebuilding cached state, not an assumed-safe rolling upgrade.
Configuration and verification
See AnnotationCacheProperties for retention and recovery settings, and AnnotationCacheConfiguration for map configuration. The service defaults are in service/src/main/resources/config/bootstrap.yml; AnnotationMessagingConfigurationValidator checks required messaging settings at startup. Set region.name, Hazelcast connectivity, and RabbitMQ connection details for your environment.
RabbitMQ integration tests
These tests protect the RabbitMQ confirm and return behavior the cache relies on—behavior that mocks cannot verify. They use a real RabbitMQ broker started by Testcontainers, so Docker is required; the tests are skipped automatically when Docker is unavailable.
From microservices/services/annotation-cache, run:
mvn -f service/pom.xml -DskipUTs -Dit.test=RabbitPublisherReturnsIT,RabbitPublisherReturnsDisabledIT,RabbitCorrelatedPublisherConfirmIT verify
Example deployments
- Docker Compose: The optional
annotation-cacheprofile indocker/docker-compose.ymlruns two replicas by default (three replicas were verified) withconsul,composeprofiles. Service settings are indocker/config/annotation-cache.yml; shared Consul settings are indocker/config/application-consul.yml. - Kubernetes / Helm: The
datawave-helm-charts/annotation-cachechart uses thedefault,k8sprofiles and Kubernetes DNS for Hazelcast discovery. Key files areannotation-cache/values.yaml(replicas and runtime args),configuration/configMapFiles/annotation-cache.yml(service and member discovery settings), andconfiguration/configMapFiles/application-k8s.yml(shared Kubernetes discovery settings), all in thedatawave-helm-chartsrepository.
After API, JDK, Hazelcast, or serialization changes, run the member/client compatibility check against the actual application dependencies, supplying SONICWEB_ROOT for your checkout. It supplements, rather than replaces, both applications' test suites. See the scaling guide for opt-in measurements.