Found while running the Valkey TCL suite (unit/hashexpire) against Dragonfly. HEXPIRE (and the other field-TTL commands) computes the absolute deadline as floor(now_in_seconds) plus the requested seconds, dropping the current sub-second. A one second expiry issued late in a wall-clock second therefore lives only milliseconds. Separately, field TTLs are journaled with their relative value rather than an absolute deadline, so a replica under lag re-applies the TTL against its own clock and can diverge.
Reproduce (the delay before HEXPIRE lands the command late in a second):
redis-cli hset h f1 v1
redis-cli hexpire h 1 FIELDS 1 f1
redis-cli hpexpiretime h FIELDS 1 f1
# deadline is only about 150 ms ahead of now, not 1000 ms
sleep 0.3
redis-cli httl h FIELDS 1 f1 # -2 (already gone after ~150 ms instead of 1 s)
redis-cli hget h f1 # nil
Found while running the Valkey TCL suite (unit/hashexpire) against Dragonfly.
HEXPIRE(and the other field-TTL commands) computes the absolute deadline as floor(now_in_seconds) plus the requested seconds, dropping the current sub-second. A one second expiry issued late in a wall-clock second therefore lives only milliseconds. Separately, field TTLs are journaled with their relative value rather than an absolute deadline, so a replica under lag re-applies the TTL against its own clock and can diverge.Reproduce (the delay before HEXPIRE lands the command late in a second):