• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Hyshmily / hotkey / 28738321635

05 Jul 2026 10:51AM UTC coverage: 90.457% (+0.04%) from 90.421%
28738321635

push

github

Hyshmily
refactor: extract interfaces for 12 core classes (Batch 1+2)

Extract interfaces from concrete classes, impls moved to impl/ subpackages:

Batch 1 (HotPath):
- CircuitBreaker, ExpireManager, SingleFlight
- KeyReporter, RuleMatcher, HealthView

Batch 2 (Supporting):
- VersionController, RingManager, HotKeyStateMachine
- SystemLoadMonitor, BbrRateLimiter, SreRateLimiter

Pattern: interface at original package, impl named XxxImpl under impl/

1296 of 1498 branches covered (86.52%)

Branch coverage included in aggregate %.

448 of 480 new or added lines in 19 files covered. (93.33%)

3690 of 4014 relevant lines covered (91.93%)

4.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/common/src/main/java/io/github/hyshmily/hotkey/autoconfigure/HotKeyRedisAutoConfiguration.java
1
/*
2
 * Copyright 2026 Hyshmily. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package io.github.hyshmily.hotkey.autoconfigure;
17

18
import com.github.benmanes.caffeine.cache.Cache;
19
import io.github.hyshmily.hotkey.Internal;
20
import io.github.hyshmily.hotkey.cache.HotKeyCache;
21
import io.github.hyshmily.hotkey.cache.cachesupport.ExpireManager;
22
import io.github.hyshmily.hotkey.cache.cachesupport.SingleFlight;
23
import io.github.hyshmily.hotkey.hotkeydetector.HotKeyDetector;
24
import io.github.hyshmily.hotkey.reporting.KeyReporter;
25
import io.github.hyshmily.hotkey.rule.RuleMatcher;
26
import io.github.hyshmily.hotkey.rule.impl.RuleMatcherImpl;
27
import io.github.hyshmily.hotkey.sharding.HealthView;
28
import io.github.hyshmily.hotkey.sharding.impl.HealthViewImpl;
29
import io.github.hyshmily.hotkey.sync.local.CacheSyncPublisher;
30
import io.github.hyshmily.hotkey.util.version.VersionController;
31
import io.github.hyshmily.hotkey.util.version.impl.VersionControllerImpl;
32
import java.util.Optional;
33
import java.util.concurrent.Executor;
34
import org.springframework.beans.factory.ObjectProvider;
35
import org.springframework.beans.factory.annotation.Qualifier;
36
import org.springframework.boot.autoconfigure.AutoConfiguration;
37
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
38
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
39
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
40
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
41
import org.springframework.boot.context.properties.EnableConfigurationProperties;
42
import org.springframework.context.annotation.Bean;
43
import org.springframework.data.redis.core.RedisTemplate;
44
import org.springframework.data.redis.core.StringRedisTemplate;
45

46
/**
47
 * Redis-enhanced auto-configuration that overrides the default
48
 * {@link HotKeyCache} with one that supports version-based stale detection.
49
 *
50
 * <p>Activates when a {@link RedisTemplate} bean is available.
51
 * {@link StringRedisTemplate} is injected as optional — if absent,
52
 * version tracking falls back to a node-local counter ({@link
53
 * io.github.hyshmily.hotkey.util.InstanceIdGenerator#getNodeId()} + {@link
54
 * java.util.concurrent.atomic.AtomicLong}) with a {@code Long.MIN_VALUE}
55
 * base, ensuring degraded versions from different JVMs occupy distinct ranges.
56
 *
57
 * <p>Runs <em>after</em> {@link HotKeyAutoConfiguration} so its
58
 * {@code @ConditionalOnMissingBean} on {@code hotKeyCache} wins over the
59
 * non-Redis variant, and after {@link RedisAutoConfiguration} so the Redis
60
 * infrastructure is ready.
61
 *
62
 * <p>Also creates a {@link RuleMatcher} with optional Redis persistence,
63
 * enabling rule CRUD operations to survive app restarts.
64
 */
65
@Internal
66
@AutoConfiguration(after = { HotKeyAutoConfiguration.class, RedisAutoConfiguration.class })
67
@ConditionalOnClass(name = "org.springframework.data.redis.core.RedisTemplate")
68
@EnableConfigurationProperties(HotKeyProperties.class)
69
public class HotKeyRedisAutoConfiguration {
3✔
70

71
  /**
72
   * Create the {@link RuleMatcher} with optional Redis persistence and broadcast support.
73
   *
74
   * <p>When a {@link StringRedisTemplate} is available, rules (blacklist/whitelist)
75
   * are persisted in Redis under the key {@code hotkey:rules}, surviving app restarts.
76
   * When a {@link CacheSyncPublisher} is available, rule changes are broadcast to
77
   * peer instances for cluster-wide consistency.
78
   *
79
   * @param redisTemplateProvider optional provider for StringRedisTemplate (Redis persistence);
80
   *                              may be absent
81
   * @param publisherProvider     optional provider for the cache sync publisher (cross-instance
82
   *                              broadcast); may be absent
83
   * @return a new RuleMatcher instance with optional Redis-backed persistence
84
   */
85
  @Bean
86
  @ConditionalOnMissingBean
87
  public RuleMatcher ruleMatcher(
88
    ObjectProvider<StringRedisTemplate> redisTemplateProvider,
89
    ObjectProvider<CacheSyncPublisher> publisherProvider
90
  ) {
91
    return new RuleMatcherImpl(
4✔
92
      Optional.ofNullable(redisTemplateProvider.getIfAvailable()),
4✔
93
      Optional.ofNullable(publisherProvider.getIfAvailable())
4✔
94
    );
95
  }
96

97
  /**
98
   * Create the Redis-enhanced {@link HotKeyCache} with version-based stale detection.
99
   *
100
   * <p>The {@link StringRedisTemplate} is optional — if absent, version tracking falls
101
   * back to a node-local counter ({@code Long.MIN_VALUE + nodeId + counter}), ensuring
102
   * graceful degradation when Redis is temporarily unavailable. The full HotKeyCache
103
   * pipeline includes: TopK detection, L1 Caffeine, SingleFlight dedup, soft/hard
104
   * expiry, cross-instance sync, reporting, rule matching, and consistent-hash routing.
105
   *
106
   * @param hotKeyDetector     the app-side TopK detector for hot-key frequency tracking
107
   * @param hotLocalCache      the L1 Caffeine cache (shared across all keys)
108
   * @param singleFlight       the deduplication layer for concurrent cache-load requests
109
   * @param expireManager      the soft/hard expiration manager for TTL control
110
   * @param syncPublisher      optional cache sync publisher for cross-instance broadcast
111
   * @param hotKeyReporter     optional hot key reporter for app-to-Worker data flow
112
   * @param hotKeyExecutor     the dedicated HotKey async executor
113
   * @param redisTemplateProvider optional provider for StringRedisTemplate (version tracking);
114
   *                              may be absent
115
   * @param properties         the HotKey configuration properties
116
   * @param ruleMatcher        the rule matcher for blacklist/whitelist evaluation
117
   * @return a new Redis-backed HotKeyCache instance
118
   */
119
  @Bean
120
  @ConditionalOnMissingBean
121
  @ConditionalOnBean({ RedisTemplate.class, HotKeyDetector.class })
122
  @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
123
  public HotKeyCache hotKeyCache(
124
    @Qualifier("hotKeyDetector") HotKeyDetector hotKeyDetector,
125
    Cache<String, Object> hotLocalCache,
126
    SingleFlight singleFlight,
127
    ExpireManager expireManager,
128
    Optional<CacheSyncPublisher> syncPublisher,
129
    Optional<KeyReporter> hotKeyReporter,
130
    @Qualifier("hotKeyExecutor") Executor hotKeyExecutor,
131
    ObjectProvider<StringRedisTemplate> redisTemplateProvider,
132
    HotKeyProperties properties,
133
    RuleMatcher ruleMatcher,
134
    ObjectProvider<HealthView> healthViewProvider
135
  ) {
136
    return new HotKeyCache(
14✔
137
      hotKeyDetector,
138
      hotLocalCache,
139
      singleFlight,
140
      expireManager,
141
      hotKeyExecutor,
142
      syncPublisher,
143
      hotKeyReporter,
144
      ruleMatcher,
145
      new VersionControllerImpl(
146
        Optional.ofNullable(redisTemplateProvider.getIfAvailable()),
4✔
147
        properties.getVersionKeyTtlMinutes()
6✔
148
      ),
149
      properties,
150
      healthViewProvider.getIfAvailable(() ->
3✔
NEW
151
        new HealthViewImpl(
×
152
          properties.getExpectedWorkerCount(),
×
153
          properties.getHeartbeat().getTimeoutMs(),
×
154
          properties.getHeartbeat().getDegradeAfterFailures()
×
155
        )
156
      )
157
    );
158
  }
159
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc