ERM redis runtime_error ai_generated true

ERR Key expiry race condition: TTL updated but key already expired

ID: redis/key-expiry-race-condition

Also available as: JSON · Markdown · 中文
85%Fix Rate
80%Confidence
1Evidence
2023-11-10First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
6.0 active
7.0 active
7.2 active

Root Cause

A race condition occurred when multiple clients simultaneously update TTL and key value, causing the key to expire before the TTL update takes effect.

generic

中文

多个客户端同时更新 TTL 和键值时发生竞态条件,导致键在 TTL 更新生效前已过期。

Official Documentation

https://redis.io/docs/latest/commands/expire/

Workarounds

  1. 95% success Use EVAL with a script: 'local val = redis.call("GET", KEYS[1]); if val then redis.call("SET", KEYS[1], ARGV[1]); redis.call("EXPIRE", KEYS[1], ARGV[2]); return 1 else return 0 end'.
    Use EVAL with a script: 'local val = redis.call("GET", KEYS[1]); if val then redis.call("SET", KEYS[1], ARGV[1]); redis.call("EXPIRE", KEYS[1], ARGV[2]); return 1 else return 0 end'.
  2. 85% success Use WATCH on the key before GET, then MULTI/EXEC to update TTL. If WATCH triggers, retry.
    Use WATCH on the key before GET, then MULTI/EXEC to update TTL. If WATCH triggers, retry.

中文步骤

  1. 使用 EVAL 执行脚本:'local val = redis.call("GET", KEYS[1]); if val then redis.call("SET", KEYS[1], ARGV[1]); redis.call("EXPIRE", KEYS[1], ARGV[2]); return 1 else return 0 end'。
  2. 在 GET 前使用 WATCH 监视键,然后使用 MULTI/EXEC 更新 TTL。如果 WATCH 触发,则重试。

Dead Ends

Common approaches that don't work:

  1. 50% fail

    SET with EX still has a race if key is deleted by another client before EXPIRE.

  2. 60% fail

    Redis transactions are not atomic for conditional operations; EXPIRE may still fail if key expires during transaction.

  3. 75% fail

    Race condition persists; repeated failures under high concurrency.