The solution is to use a Lua script:
local time = redis.call('TIME')
local ts = time[1]..string.format('%06d', time[2])
return redis.call('ZADD', KEYS[1], ts, ARGV[1])
Here we use Redis TIME
command. The command returns:
- unix time in seconds
- microseconds
So we can concatenate these two and use a microsecond-timestamp. We need to zero-pad the microseconds part.
Since sorted sets are good with integer values up to 2^53, our timestamp is safe all the way up to the year 2255.
This is Redis-Cluster-safe as we store in one key. To use multiple keys, make sure to land them on the same node using hash tags if you want to compare timestamps.
You can modify the script to use lower than microsecond resolution.
Here the EVAL
command, simple pass key and value as arguments, no need to create the sorted set before hand:
EVAL "local time = redis.call('TIME') local ts = time[1]..string.format('%06d', time[2]) return redis.call('ZADD', KEYS[1], ts, ARGV[1])" 1 ssetKey myVal
As always, you may want to load the script and use EVALSHA
.
> SCRIPT LOAD "local time = redis.call('TIME') local ts = time[1]..string.format('%06d', time[2]) return redis.call('ZADD', KEYS[1], ts, ARGV[1])"
"81e366e422d0b09c9b395b5dfe03c03c3b7b3bf7"
> EVALSHA 81e366e422d0b09c9b395b5dfe03c03c3b7b3bf7 1 ssetKey myNewVal
(integer) 1
A note on Redis version. If you are using:
- Redis Version before 3.2: sorry, you cannot use
TIME
(non-deterministic command) and then write with ZADD
.
- Redis Version greater than 3.2 but < 5.0: Add
redis.replicate_commands()
on top of the script. See Scripts as pure functions
- Redis 5.0 an up: you are good.