Skip to content

1.1.4

Choose a tag to compare

@Hyshmily Hyshmily released this 11 Jun 07:54

Version & Platform

  • JDK 17 Downgrade — Minimum Java version lowered from 25 to 17. Replaced JDK 21+ APIs (Thread.startVirtualThread(), unnamed _ lambda parameters) with JDK 17-compatible equivalents.
  • Version Bump — All POMs, READMEs, and metadata updated to 1.1.4.

Consistent Hash Ring (ADR 0005, 0006, 0007)

  • Consistent Hash Ring — New sharding layer using Guava murmur3_32_fixed() with TreeMap + virtual nodes (default 500/node). Lock-free reads via volatile ring snapshot. Collision probability <3% with 500 vnodes × 100 Workers.
  • RingManager — Orchestrates ring with auto (heartbeat-discovered) and manual (operator override) modes. Heartbeat timeout: 5s default.
  • WorkerHealthMonitor Eliminated — Replaced by RingManager. Node identity migrated from int shardIndex to String nodeId across all modules (WorkerMessage, report queues, heartbeats).
  • Key-Based Worker RoutingrouteNode(key) maps cache keys to responsible Worker nodes via consistent hash ring with liveness predicate.

Decentralized Config Gossip (ADR 0003)

  • Decentralized Config GossipWorkerConfigNegotiator listens for heartbeat-borne state-machine config from peers. Applies when remote timestamp > local. Falls back to WorkerProperties defaults if no heartbeat within 3s.
  • Heartbeat Enriched with ConfigbroadcastHeartbeat() now carries confirmCount, coolCount, preCoolGraceCount, and monotonic configTimestamp in AMQP headers. No dedicated config store needed.
  • configTimestampCounter — Shared AtomicLong for config-change ordering across the Worker cluster.

Graceful Degradation (ADR 0001, 0009)

  • Local Promotion with Worker-Aware FallbackpromoteLocalHotkeyIfNeeded() upgrades NORMAL always; COOL only when all Workers dead. Local TopK takes over during Worker outage; self-heals via decisionVersion on Worker recovery.
  • Graceful Degradation Path — When isAnyWorkerAlive() == false: COOL entries become promotable, Reporter drops batches silently, Worker recovery auto-reasserts authority.
  • Null-Safe evaluateRule() — Returns ALLOW instead of throwing when hotKeyCache is null (Worker-only mode).

Dual Version Space (ADR 0008)

  • Two-Version ArchitecturedataVersion (Redis INCR, may degrade to node-local counter) for cross-instance sync; decisionVersion (Worker AtomicLong, never degrades) for HOT/COOL ordering. Orthogonal.
  • VersionGuard Refactored — Overloaded methods accepting CacheEntry directly for use inside compute() blocks, eliminating redundant getIfPresent calls.
  • Degraded Comparison — 4-case comparison prevents degraded dataVersion from overwriting normal ones across instances.

Performance & Concurrency

  • Atomic Cache Operations — All writes use caffeineCache.asMap().compute() instead of blind put(). Worker-managed entries (HOT/COOL) preserved via isWorkerManagedEntry() guard.
  • SingleFlight Exception-Only Invalidate (ADR 0002) — Removed whenComplete invalidate; only catch-block invalidates. Normal completions stay cached via Caffeine expireAfterWrite.
  • Batch Invalidation Chunking — Large key sets split into 1000-key AMQP messages to prevent oversized message rejection.
  • SpEL Expression Caching — Parsed Expression objects cached in ConcurrentHashMap across invocations.
  • Fallback Method Caching — Resolved methods cached in ConcurrentHashMap to avoid repeated reflection.
  • CacheExpireManager Jitter — Hard/soft expire timestamps apply ±10% jitter via ThreadLocalRandom to prevent thundering herd.
  • Graceful Executor ShutdownThreadPoolTaskExecutor waits for in-flight tasks (60s timeout).
  • Prefetch Count — Both listener containers set prefetchCount=5 for backpressure control.

Composable Annotation System

  • HotKeyCacheTTL — Per-method hard/soft TTL override. Replaces HotKey.hardTtlMs() / .softTtlMs().
  • Intercept — READ marker: hot key → skip original method, return Fallback or peek().
  • Fallback — Declares fallback value/method for READ. Replaces HotKey.fallbackEnabled() / .fallback(). Triggered on blacklist block, Intercept hot key, or cache loader exception.
  • condition() SpEL — When false, cache bypassed entirely.
  • unless() SpEL — Evaluated after cache load; #result available. Result accepted as-is, cache still used.
  • HotKeyAspect Rewrite — 281→391 lines. 7-step priority chain: blacklist → condition → unless → notifyLocalDetector → intercept → TTL resolution → cache lookup.
  • Blacklist IntegrationRuleAction.BLOCK support with HotKeyBlockedException.

Micrometer & Actuator

  • HotKeyMicrometerAutoConfiguration — 17+ custom gauges: hotkey.topk.*, hotkey.reporter.* (queue depth/dropped/expired/pending), hotkey.singleflight.*, hotkey.version.degraded, hotkey.sync.dedup, hotkey.worker.alive, hotkey.worker.tracked, plus Caffeine L1 metrics.
  • RingEndpoint/actuator/hotkeyring with full CRUD (GET, POST addNode, DELETE removeNode, POST rebuild).
  • StateMachineEndpoint/actuator/hotkey/worker/state with GET (config) and POST (update confirmCount/coolCount/preCoolGraceCount). Changes propagate via heartbeat gossip.

Expanded Public API

  • getLocalCache() — Exposes raw Caffeine Cache for introspection.
  • notifyLocalDetector() — Feeds local TopK without Worker report.
  • isWorkerHotKey() — O(K) list iteration → O(1) contains().

Configuration Changes

  • confirm-duration-ms Default — 2000 → 300. HOT promotion within 300ms (was 2s).
  • evict-interval-ms — New (default 30000) for dedicated eviction.
  • shard-count / shard-index Removed — Replaced by auto-generated nodeId.
  • Consistent Hashing Properties — New enabled (default true) and virtual-nodes (default 500).
  • ConditionalOnProperty Prefixhotkeyhotkey.annotation (functionally equivalent).

AMQP Improvements

  • JSON Message ConverterJackson2JsonMessageConverter for report messages (was Java serialization).
  • AmqpException Handling — New try-catch in CacheSyncPublisher and WorkerListener.
  • Ack-Before-Update (ADR 0004) — Ack before cache write for at-most-once delivery; self-healing via periodic broadcast.
  • Shared ObjectMapperstatic final instance instead of per-call allocation.

Documentation

  • 9 ADRsdocs/adr/0001–0009 covering all architecture trade-offs.
  • ANNOTATION.md — Composable annotation system docs.
  • CONTEXT.md — Domain glossary with canonical term definitions.
  • Full Javadoc — Every public class, method, and field documented.

Test Coverage

  • 3 New SuitesMicrometerAutoConfigurationTest, ConsistentHashRingTest, RingManagerTest.
  • HotKeyEndpointTest — 2→9 tests.
  • Total — 379 passing (332 common + 47 worker).