fix(cache): set/expire/getOrLoad 对 ttl<=0 fail-fast,杜绝 expire 误删 key

expire(key, ttl<=0) 经 applyJitter 透传 0/负值,Redis EXPIRE 非正值会立即删 key
并返回 1,使"续期"静默删数据且报 true;set(ttl<=0) 则下发非法过期抛
RedisSystemException。统一在 set/expire/doGetOrLoad 入口 requirePositiveTtl 校验,
非正 TTL 直接抛 IllegalArgumentException。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-06-26 09:46:55 +08:00
parent 8dc714b0ad
commit ba2606ea46
2 changed files with 34 additions and 0 deletions

View File

@@ -240,4 +240,28 @@ class RedisCacheEnhanceTemplateTest {
User got = template.getOrLoad("user:1", User.class, 60, () -> new User(1L, "fresh"));
assertEquals("fresh", got.getName());
}
// ---- #1+#2: ttl<=0 入口校验(fail-fast,不下发非法过期) ----
@Test
void setRejectsNonPositiveTtl() {
User u = new User(1L, "a");
assertThrows(IllegalArgumentException.class, () -> template.set("user:1", u, 0));
assertThrows(IllegalArgumentException.class, () -> template.set("user:1", u, -1));
verify(valueOps, never()).set(anyString(), anyString(), anyLong(), any());
}
@Test
void expireRejectsNonPositiveTtl() {
assertThrows(IllegalArgumentException.class, () -> template.expire("user:1", 0));
assertThrows(IllegalArgumentException.class, () -> template.expire("user:1", -5));
verify(redis, never()).expire(anyString(), anyLong(), any());
}
@Test
void getOrLoadRejectsNonPositiveTtl() {
props.getBreakdown().setEnabled(false); // 避免跑红时走入等待自旋
assertThrows(IllegalArgumentException.class,
() -> template.getOrLoad("user:1", User.class, 0, () -> new User(1L, "a")));
}
}