Files

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.
  • service runs Hazelcast members. AnnotationCacheConfiguration defines two fixed shared maps: annotations and authorization-specific source-lookup markers. Fixed maps avoid creating a map per document.
  • api provides 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-cache profile in docker/docker-compose.yml runs two replicas by default (three replicas were verified) with consul,compose profiles. Service settings are in docker/config/annotation-cache.yml; shared Consul settings are in docker/config/application-consul.yml.
  • Kubernetes / Helm: The datawave-helm-charts/annotation-cache chart uses the default,k8s profiles and Kubernetes DNS for Hazelcast discovery. Key files are annotation-cache/values.yaml (replicas and runtime args), configuration/configMapFiles/annotation-cache.yml (service and member discovery settings), and configuration/configMapFiles/application-k8s.yml (shared Kubernetes discovery settings), all in the datawave-helm-charts repository.

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.