Skip to content

Releases: Hyshmily/hotkey

v1.1.54

Choose a tag to compare

@Hyshmily Hyshmily released this 02 Jul 11:24

Highlights

  • Circuit breaker — New HotKeyCircuitBreaker protects remote cache-load suppliers; SingleFlight checks allowRequest() before queuing; returns stale Caffeine entry on open breaker.
  • Null-value cachingNullValue.INSTANCE cached with configurable TTL (default 10s) when reader returns empty.
  • HeavyKeeper rewrite — Sliding-window ring buffer (windows[] + slotSums[]) replaces flat long[]; ConcurrentHashMap<String, Node> + ReentrantLock for TopK membership (hot path lock-free); LongAccumulator for striped count write; locCache memoizes hash+fingerprint+bucket indices; volatile long minPqCount for O(1) fast-rejection; 65536-entry decay LUT; adaptive stripe count; parallel addDirect() batch feed.
  • BufferedCounter replaces Caffeine for reporter counters; configurable buffer/flush/eagerSwap params; HotKeyThreadFactory naming.
  • Parallel ReportConsumerparallelStream() chunked (1000 keys); batch addDirect() TopK feed; pre-allocated nextDecisionVersion(); serial drain avoids AMQP channel contention; fire-and-forget broadcast.
  • State machine cool 15s→10mincoolDurationMs 15000→600000, preCoolGraceMs 5000→60000.
  • SlidingWindowDetector memoryAtomicLong[]AtomicLongArray; ~94% reduction (80MB→5MB/100k keys).
  • Cluster health simplified — Removed degraded flag, manual ring override; minAliveWorkers quorum. Heartbeat defaults: timeout 30s→10s, verify 1500ms→5000ms.

Breaking / API

  • CacheLoader SPIFunction<String, Object>CacheLoader interface.
  • RingManager auto-mode only; addNode()/removeNode()/resetToAuto()/isManualMode() removed.
  • HotKeyEndpoint — Actuator @Endpoint → Spring MVC @RequestMapping.
  • ttlJitterEnabled removed — jitter always on; ratio 0.1→0.05.
  • ClusterHealthView constructor signature changed (no degraded param).

Infrastructure

  • TimeSource — Caches System.currentTimeMillis() on daemon thread (5ms tick); all hot-path expiry migrated.
  • HotKeyThreadFactory — Daemon, named, NORM_PRIORITY; replaces all ad-hoc Thread creation.
  • Dedicated hotKeySyncScheduler — Isolated from reporter flush scheduler.
  • @Scheduled removed — Tasks use ScheduledExecutorService.scheduleWithFixedDelay() directly.

v1.1.53

Choose a tag to compare

@Hyshmily Hyshmily released this 25 Jun 09:58

Full-Link Optimization & Bug Fixes

  • isLocalHotKey() HeavyKeeper fallback — When L1 cache entry is a CacheEntry with KeyState.NORMAL, added a fallback check to hotKeyDetector.contains() to prevent local detection from always returning false before Worker broadcast arrives.

  • Reporter flush lost counters on empty route — Changed sumThenReset() to first call sum() to read, then confirm route, then sumThenReset() to prevent burst counters from being silently discarded when Worker is not ready.

  • BBR maxInFlight floor fixmaxInFlight() now returns Math.max(1, floor(...)) to prevent BBR deadlock when minRT is too small (resulting in 0).

  • ThresholdLearner dynamic threshold only rises — Lower bound changed from Math.max(10, ...) to Math.max(hotThreshold, ...) to prevent lowering a fixed threshold of 1000 to 20 under low QPS.

  • Worker heartbeat robustness with DependsOn("rabbitAdmin")WorkerHeartbeatProducer now waits for RabbitAdmin to complete exchange declaration before starting heartbeat sending, eliminating the first NOT_FOUND error.

  • initialDelay=pingIntervalMs — First heartbeat delay changed from 0 to pingIntervalMs (default 1s), working with @DependsOn to allow Worker to start independently.

  • StateMachine independent time slicing — StateMachine now has its own sm-duration-ms (500) and sm-slices (10), independent of the sliding-window detector. confirmCount = ceil(100 / 50) = 2.

  • heartbeat.timeout-ms default — Changed from 3000 to 30000 (30 seconds) for production stability.

  • sliding-window.duration-ms default — Changed from 500 to 1000 (1 second) to cover intermittent burst hotspots.

  • warmup-jitter-ms (sync) default — Changed from 100 to 50 (50 milliseconds).

  • warmup-jitter-ms (worker-listener) default — Changed from 100 to 50 (50 milliseconds).

  • confirm-duration-ms default — Changed from 150 to 100 (2-window confirmation).

v1.1.51

Choose a tag to compare

@github-actions github-actions released this 23 Jun 14:14

Distributed Lock Support

  • LockProvider — New LockProvider interface defining tryLock(key, expire, unit) and overloads with explicit retry counts. AutoReleaseLock (@FunctionalInterface extends AutoCloseable) for try-with-resources usage.
  • RedisLockProvider — Redis-backed implementation using SET NX PX with UUID-based safe release. Exponential backoff retry, configurable lock/inquiry/unlock counts. Inner class RedisLockHandle implements AutoReleaseLock.
  • HotKeyLockAutoConfiguration — Auto-wires LockProvider bean when StringRedisTemplate is available. Registered in AutoConfiguration.imports. Graceful degradation via @ConditionalOnClass (no-op when Redis absent).
  • HotKey Facade — New 4th constructor parameter LockProvider (nullable). New public methods: tryLock(key, expire, unit), tryLock(key, expire, unit, lockCount, inquiryCount, unlockCount), tryLockAndRun(key, expire, unit, action), tryLockAndRun(key, expire, unit, action, lockCount, inquiryCount, unlockCount).
  • HotKeyProperties — 3 new config properties: tryLockLockCount (default 2), tryLockInquiryCount (default 1), tryLockUnlockCount (default 2).
  • HotKeyConstants — New REDIS_LOCK_KEY_PREFIX = "hotkey:lock:".

Deployment Mode Enforcement

  • HotKeyModeException — New RuntimeException with operation, currentMode, requiredMode fields. Thrown when a HotKey API is called in an unsupported deployment mode.
  • requireAppCache / requireAppDetector — Former single requireCache() throwing UnsupportedOperationException replaced by two methods, both throwing HotKeyModeException: requireAppCache(operation) guards L1 cache operations; requireAppDetector(operation) guards local TopK detector operations. Operation name strings provide precise error messages.
  • Mode query methods — New public methods: isApp() (cache available), isWorker() (Worker TopK available), isAppOnly() (pure App mode), isWorkerOnly() (pure Worker mode).
  • currentModeLabel() — New private helper generating human-readable deployment mode labels ("App-only mode", "Worker-only mode", "Coexistence mode", "Uninitialized mode").
  • Stricter read method guardsget(), getWithSoftExpire(), etc. now call both requireAppCache() and requireAppDetector() (reference only checked cache).
  • notifyLocalDetector guards — All 5 notifyLocalDetector*() methods now call requireAppDetector() instead of NPE-ing in Worker-only mode as in the reference.
  • computeIfAbsent simplificationcomputeIfAbsent() and computeIfAbsentWithSoftExpire() convenience overloads no longer call requireAppCache() directly — they delegate to inner get()/getWithSoftExpire() which perform their own guard checks.

invalidateAll Rename

  • invalidateAll → invalidateAllLocal — The no-arg invalidateAll() method renamed to invalidateAllLocal(), emphasizing local-only clear semantics (no broadcast). invalidateAll(String...) and invalidateAll(Collection) remain unchanged (varargs overloads still exist — they broadcast batch invalidations).
  • putLocal silent no-op — All three putLocal() overloads now silently return in Worker-only mode (if (hotKeyCache == null) return;) instead of throwing. Design choice — local writes should always be safe.

HotKeyCache Resilience and Correctness

  • Read path try-catchget(), getWithSoftExpire(), and peek() now wrap their logic in try-catch: HotKeyBlockedException re-thrown as-is; all other RuntimeException logged and return Optional.empty(). Prevents internal failures from propagating to callers.
  • Writer exception handlingputThrough() now wraps writer.run() in try-catch; logs error and skips cache update when writer throws. Fixes partial-write issue where cache was updated despite data source failure.
  • buildPutThroughEntry version guardbuildPutThroughEntry() now calls VersionGuard.shouldSkipForSync(). If existing entry's dataVersion is already >= the new version, the existing entry is preserved unchanged. Prevents stale writes from overwriting newer data.
  • Conditional TOCTOU re-read — Re-reads from cache only when side effects actually occurred (real promotion or report not skipped), instead of always re-reading. Minor performance optimization.

HotKeyReadQuery Single-Execution Guard

  • AtomicBoolean executed — New executed field initialized AtomicBoolean(false). execute() checks compareAndSet(false, true); throws IllegalStateException("HotKeyReadQuery can only be executed once") if already invoked on the same builder. Prevents accidental double execution.

CacheSyncListener Async Error Handling

  • try-catch wrapping async task — Runnable tasks scheduled on syncScheduler are now wrapped in try-catch with logging of type/key/version. Catches uncaught exceptions that would otherwise be swallowed.

VersionGuard Worker Epoch + NodeId

  • shouldSkipForWorker 5-arg signature — New shouldSkipForWorker(CacheEntry, long, String, long) with incomingNodeId and incomingEpoch parameters. Logic:
    • Incoming epoch > existing epoch → accept (Worker restart — ADR-0010)
    • Incoming epoch < existing epoch → skip (stale)
    • Same epoch, same nodeId → normal ordering (existing >= incoming → skip)
    • Different nodeId, same epoch → accept (cross-Worker ownership transfer)
  • shouldSkipForWorker Cache-level overload — New 5-arg shouldSkipForWorker(Cache, String, long, String, long) overload. 3-arg version now delegates to 5-arg with null nodeId and 0 epoch.

CacheEntry Epoch Tracking

  • New field decisionNodeIdprivate final String decisionNodeId. Tracks which Worker node produced the decisionVersion. Used by VersionGuard.shouldSkipForWorker for per-Worker version space partitioning.
  • New field decisionEpochprivate final long decisionEpoch. Tracks Worker restart counter epoch. Used by VersionGuard.shouldSkipForWorker for restart detection (ADR-0010).

VersionController Lua Script Optimization

  • Pre-compiled script — Lua script INCR_SCRIPT now defined as a static final field instead of creating a new DefaultRedisScript object on every nextVersion() call. Avoids re-creating script object on every version allocation.
  • Simplified script content — Always calls EXPIRE after INCR now (conditional if tonumber(ARGV[1]) > 0 check removed).

HotKeySpringCache nullCachedKeys Removal

  • nullCachedKeys set removed — Entire nullCachedKeys (ConcurrentHashMap.newKeySet()) removed. lookup() no longer checks it, put()/evict()/clear() no longer manage it, get(Object, Callable) no longer populates it. Null caching behavior now handled entirely through NullValue sentinel inside CacheEntry without a separate keyset. Removes import java.util.Set and import java.util.concurrent.ConcurrentHashMap.

ClusterHealthView Dynamic Worker Count

  • knownWorkerCount made mutableknownWorkerCount changed from final to volatile with setter. @RequiredArgsConstructor removed; explicit constructor added.
  • isClusterHealthy() fallback — When knownWorkerCount <= 0, isClusterHealthy() now returns aliveCount > 0 (falls back to observed alive Workers) instead of hardcoded false as in reference. Enables backward compatibility.
  • Getter added@Getter added on knownWorkerCount.

Package Reorganization

  • HeavyKeeper typo fix — Package renamed from hotkeydetector/heavykepper/ (double p) to hotkeydetector/heavykeeper/. All imports updated.
  • Sync package split — Flat sync/ package split into sync/local/ (SyncMessage, CacheSyncPublisher, CacheSyncListener, CacheSyncProperties), sync/worker/ (WorkerMessage, WorkerListener, WorkerListenerProperties, WorkerHeartbeatVerifier, WorkerHeartbeatMessage), and sync/distributedlock/ (LockProvider, AutoReleaseLock, impl/RedisLockProvider). All imports updated.
  • Version classes movedVersionController.java and VersionGuard.java moved from sync/ to util/version/.
  • ClusterHealthView movedClusterHealthView.java moved from sync/ to sharding/.

Transaction Support Documentation

  • Rollback behaviorTransactionSupport Javadoc adds <p><b>Rollback behavior:</b> section documenting that runNowOrAfterCommit actions are NOT executed on transaction rollback.

1.1.5-SNAPSHOT

Choose a tag to compare

@Hyshmily Hyshmily released this 19 Jun 09:46

Broadcast Suppression Annotation

  • Broadcast — New @Target(METHOD) annotation with boolean value() default true. When set to false, suppresses cross-instance cache sync messages. Supported on @Cacheable, @CachePut, and @CacheEvict.
  • HotKeyCacheContext — New skipBroadcast field and isSkipBroadcast() getter. Context stores flag when any companion annotation is non-default. Applied by HotKeyCacheExtensionAspect before method execution.
  • HotKeyCacheExtensionAspect — New @Around("@annotation(cachePut)") and @Around("@annotation(cacheEvict)") pointcuts. Reads @Broadcast and sets skipBroadcast in context. Existing aroundCacheable() also reads @Broadcast.
  • HotKeySpringCacheput(), evict(), and null-caching path in get(key, loader) check isSkipBroadcast(). When true, calls putLocal()/evictLocal() instead of putThrough()/invalidate(), avoiding broadcast, version bump, and hot-key detection.
  • HotKeyCacheTTL@Target expanded to include ElementType.TYPE, allowing class-level TTL defaults.

1.1.5.Beta

Choose a tag to compare

@Hyshmily Hyshmily released this 17 Jun 08:17

Fluent Cache Read/Write API

  • HotKeyReadQuery — Chain-style multi-level reads with withPrimary, thenExecute, allowNull, allowBroadcast, and orElseThisTime. Preserves L1 caching, hot-key detection, and SingleFlight via HotKey core API.
  • HotKeyWriteCommand — Fluent write operations (putThrough, putBeforeInvalidate, invalidate) with TTL overrides. All commands automatically enforce blacklist rules.

Local-Only Writes

  • putLocal — Added to HotKeyCache and HotKey facade. Writes to local Caffeine without version bump, broadcast, or hot-key detection. Preserves existing entry metadata.

Broadcast Control

  • allowBroadcast / notAllowBroadcast — Callers control whether fallback results are broadcast via putThrough. Default is false (no broadcast), keeping reads silent by default.

Blacklist & Null Handling Fixes

  • Blacklist ConsistencyputThrough and putBeforeInvalidate now throw HotKeyBlockedException on blocked keys, matching the behavior of get/peek.
  • Null Sentinel Unification — All internal null caching uses NullValue.INSTANCE in putThrough and fallback caching, avoiding Caffeine null rejection.

Documentation Clarifications

  • No Broadcast on Readsget and getWithSoftExpire never broadcast; only putThrough/invalidate and explicitly allowBroadcast-enabled fallbacks trigger REFRESH.

1.1.4-SNAPSHOT

Choose a tag to compare

@Hyshmily Hyshmily released this 12 Jun 15:16

Dual-Buffer Counter

  • Lock-Free Batching Layer — Adds a dual-buffer counter before HeavyKeeper. Per-get() add(key, 1) calls are merged into periodic (100-500ms) add(key, N) batch submissions. Reduces lock contention from O(N) to O(1) under ultra-high concurrency (millions QPS).
  • Transparent to Callers — No API changes required. The batching layer operates silently, preserving existing get() semantics while dramatically reducing HeavyKeeper’s synchronization overhead.
  • Inspired by HotCaffeine — Adopts the proven dual-buffer design from HotCaffeine’s DefaultKeyCounter, adapted for HotKey’s HeavyKeeper integration.

Reporter Self-Protection (BBR + CPU Fusion)

  • BBR + CPU Fusion — Integrated BBR congestion control with CPU EMA into Reporter flush. BbrRateLimiter.tryAcquire() decides to admit or drop each batch based on concurrency budget and CPU load.
  • Two‑Zone Decision — Below 80% CPU: permissive (admit if concurrency within budget OR not in cooldown). Above 80%: strict (admit only if concurrency within budget). Prevents overload amplification.
  • CPU EMA — Smoothed via cpuDecay=0.95, 500ms interval, avoids thrashing on spikes.
  • BBR Sliding Window — 10s window, 100 buckets, tracks max pass rate & min RTT to compute safe concurrency limit.
  • Backpressure — Drops logged at DEBUG, metric hotkey.reporter.bbr.dropped. Self‑throttles before RabbitMQ/Worker overload.
  • Default Enabledhotkey.local.reporter.enabled=true. Zero overhead when healthy.

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).

1.1.3

Choose a tag to compare

@Hyshmily Hyshmily released this 06 Jun 05:29
  • Version Cohesion — Unified version management: Eliminates version comparison bugs across Redis and local fallback.
  • Increase Worker Heartbeat Mechanism — Added heartbeat mechanism for Worker nodes to monitor liveness and detect failures.
  • Improve Endpoint Calls — Enhanced Actuator endpoints with additional metrics: report queue depth, capacity, expired count, and queue full count. Provides better observability for backpressure and system health.

1.1.2

Choose a tag to compare

@Hyshmily Hyshmily released this 02 Jun 07:43
  • Report Backpressure MechanismHotKeyReporter.flush() changed to enqueue via LinkedBlockingQueue.offer(timeout), no longer direct publish. When queue is full, after 100ms timeout it discards with WARN, backpressure naturally flows to Caffeine 30s eviction for rate limiting.
  • Dedicated Consumer Thread PoolHotKeyReporter starts N daemon consumer threads (max(1, shardCount/2), configurable consumerCount) consuming from bounded queue and publishing to RabbitMQ. Each consumer checks 5s expiration when dequeuing, silently discarding expired entries.
  • New Configuration PropertiesHotKeyProperties added queueCapacity (default 10000), queueOfferTimeoutMs (default 100), consumerCount (default 0 = auto), prefix hotkey.local.*.
  • Actuator Queue MetricsHotKeyEndpoint added 4 monitoring fields: reportQueueDepth, reportQueueCapacity, reportExpiredCount, reportQueueFullCount, injected via ObjectProvider<HotKeyReporter> into HotKeyActuatorAutoConfiguration.
  • Reporter Lifecycle ManagementHotKeyReportAutoConfiguration uses initMethod = "start" and destroyMethod = "stop" to manage HotKeyReporter dispatcher threads.
  • Negative Shard Routing FixHotKeyReporter shard routing changed from Math.abs(key.hashCode()) % shardCount to Math.floorMod(key.hashCode(), shardCount). Eliminates Integer.MIN_VALUE edge case where Math.abs(Integer.MIN_VALUE) returns negative causing array index out of bounds.
  • Checked Exception Propagation FixHotKeyAspect replaced throw new RuntimeException(e) with Lombok-free sneakyThrow(e), preserving original checked exception types through Supplier/Runnable lambdas in handleRead and handleWrite, so callers don't need to catch RuntimeException wrapper.
  • Fixed known bugs

1.1.1

Choose a tag to compare

@Hyshmily Hyshmily released this 01 Jun 05:33
  • Fallback Version Negative SpacefallbackVersion() migrated to Long.MIN_VALUE + counter (negative space). This eliminates the bug where degraded versions suppressed normal broadcasts in sendDeduped numeric comparison. Normal versions (positive) always dominate degraded versions (negative).
  • Invalidate GuardhandleInvalidate now includes a shouldSkipForSync guard, preventing degraded INVALIDATE broadcasts from incorrectly clearing normal L1 entries.
  • Worker HOT Promotion on Redis Unavailable — When Redis returns null during handleHot, the method promotes an existing degraded L1 entry (if present) to HOT, preventing permanent loss of Worker HOT decisions.
  • SyncMessage Default FixSyncMessage.from() default isVersionDegraded changed from true to false, preventing silent data sync failures when the header is missing.
  • Multi-Module Splithotkey:1.1.0 refactored into hotkey-parent (pom) with common/ and worker/ modules. The common artifact published to Maven Central; worker is a standalone Spring Boot app (maven.deploy.skip=true). Worker-only classes moved out of the shared artifact, reducing App-only footprint.
  • Coexistence Mode Removal — Removed exclusive-mode and hotkey.worker.mode (COEXISTENCE/EMBEDDED/STANDALONE). Deployment simplified to two modes: App-only / Worker-only. Replaced condition annotation with @ConditionalOnProperty(prefix="hotkey.worker", name="enabled", havingValue="false", matchIfMissing=true).
  • Annotation Support — Added annotation/ package and @HotCache annotation (renamed to avoid conflict with HotKey facade). Supports SpEL key(), three operation types (READ/WRITE/INVALIDATE), and per-annotation TTL/soft-expire overrides. HotKeyAspect injects HotKey facade; requires spring-boot-starter-aop (<optional>true</optional>). HotKeyAnnotationAutoConfiguration registered as the 9th auto-configuration class.
  • Worker Configuration RestructureWorkerProperties.java reorganized into 9 nested inner classes (Routing, Messaging, SlidingWindow, Threshold, StateMachine, DynamicThreshold, TopKValidation, HeavyKeeper) plus a flat enabled field. Auto-configuration property access paths updated to nested getters; fixed @Scheduled SpEL; retained backward-compatible delegate methods.
  • Degraded Version Upgrade — Replaced System.nanoTime() fallback with (nodeId << 32) | counter. Uses InstanceIdGenerator (UUID file + hostname fallback) to derive node ID and a shared AtomicLong. Guarantees cross-JVM ordering without clock drift.
  • Full-Path Reportingget() / getWithSoftExpire() now call hotKeyReporter.record() on both L1 hit and L2 miss paths (previously only hot-key misses). Worker receives complete access patterns rather than only the hot-key subset.
  • Dependency Additions — Added spring-amqp and spring-boot-starter-aop as <optional>true</optional> to the common module. Bumped Guava version to 32.1.3-jre in <dependencyManagement>.
  • AutoConfiguration.imports Update — Removed WorkerAutoConfiguration from the shared imports file (now scanned by @SpringBootApplication in worker module). Added HotKeyAnnotationAutoConfiguration. Total 9 entries maintained.
  • Documentation & Readability — README deployment tables collapsed to two modes; Worker config reorganized with group header rows and nested YAML examples. Removed coexistence references from CLAUDE.md/AGENTS.md. application.yml partitioned with # ── Section ── markers. Retained Apache 2.0 license headers.