Calling TIME (i.e. non-deterministic commands) inside EVAL

1,400 views
Skip to first unread message

Michael Jackson

unread,
Nov 13, 2012, 3:06:28 PM11/13/12
to redi...@googlegroups.com
I came across this issue the other day when I was trying to work up a little Lua script to automatically generate id's inside Redis that include the current timestamp. As it says in that thread, Redis won't let you alter the dataset in any way after you call a non-deterministic command like TIME inside an EVAL.

redis> eval "local now = redis.call('time') redis.call('set', 'now', 1)" 0
(error) ERR Error running script (call to f_a3bd993bedc6213499b6be5d6b1ce6699b89b0e9): Write commands not allowed after non deterministic commands

I have two questions about this:

1. I was just wondering why this needs to be the case. For generating unique ids it would be really useful to be able to get the current time and combine it perhaps with some other unique counter (e.g. see how Instagram does it with PostgreSQL) inside a Lua script.

2. I'm not sure if this is a bug, but the SET example that I used above doesn't actually return an error (using Redis 2.6.4) when you use the local now as the value.

redis> eval "local now = redis.call('time') redis.call('set', 'now', now)" 0
(nil)

--
Michael Jackson
@mjackson

Michael Jackson

unread,
Nov 13, 2012, 3:13:25 PM11/13/12
to redi...@googlegroups.com
BTW, I'm basing my questions on the discussion of this topic inside the Redis docs on EVAL:

> Redis will block the script with an error if a script calls a Redis command able to alter the data set after a Redis random command like RANDOMKEY, SRANDMEMBER, TIME. This means that if a script is read-only and does not modify the data set it is free to call those commands. Note that a random command does not necessarily mean a command that uses random numbers: any non-deterministic command is considered a random command (the best example in this regard is the TIME command).

The docs are clear about what should happen, but they don't say why this is the case.

--
Michael Jackson
@mjackson

Felix Gallo

unread,
Nov 13, 2012, 3:15:35 PM11/13/12
to redi...@googlegroups.com
if I remember correctly, it's because commands are sent to slaves, rather than state.  If you called a redis script on the master, it will call it on the slave.  If those two scripts have different return values, then you suddenly have a problem.

F.

--
You received this message because you are subscribed to the Google Groups "Redis DB" group.
To post to this group, send email to redi...@googlegroups.com.
To unsubscribe from this group, send email to redis-db+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/redis-db?hl=en.

Salvatore Sanfilippo

unread,
Nov 14, 2012, 6:08:30 AM11/14/12
to Redis DB
On Tue, Nov 13, 2012 at 9:13 PM, Michael Jackson <mjija...@gmail.com> wrote:
> The docs are clear about what should happen, but they don't say why this is
> the case.

If you put a script with TIME inside AOF or in the replication link,
the result will not be the same as it will be in the master.

The simple work around is, when you really need to do so, to call TIME
as a normal command, and then call the script giving the value you got
from TIME as parameter of the script.

Cheers,
Salvatore

--
Salvatore 'antirez' Sanfilippo
open source developer - VMware
http://invece.org

Beauty is more important in computing than anywhere else in technology
because software is so complicated. Beauty is the ultimate defence
against complexity.
— David Gelernter

Archie R

unread,
Apr 26, 2015, 8:31:01 PM4/26/15
to redi...@googlegroups.com


I see several posts looking for the same answer.    We're trying to add timestamps to JSON encoded strings.  We wanted to use Redis TIME as the source of the timestamp (we have several servers and server redis).

Using TIME in a separate call will add some overhead and I think might have trouble when we're sharding.   We're not sure our TIME command will run on the same server as our SET which we use the result in when we follow up.

Josiah Carlson

unread,
Apr 27, 2015, 1:07:35 PM4/27/15
to redi...@googlegroups.com
Are you running NTP to keep your machine times reasonably synced? Because if your concern is "I ran TIME on Redis X, but when I set my data on Redis Y, the clock output is substantially different", then NTP can solve that problem pretty effectively.

Similarly, if you are getting to the point of trusting multiple sources of time, why not run NTP on the machines your clients are running on, and just use the timestamp produced on your clients?

If you'd prefer to rely on a single source for timestamps, it might make sense to designate a specific server as your one source of truth for the current time, and make efforts to ensure that you are only fetching time from that one server.

 - Josiah


--
You received this message because you are subscribed to the Google Groups "Redis DB" group.
To unsubscribe from this group and stop receiving emails from it, send an email to redis-db+u...@googlegroups.com.

To post to this group, send email to redi...@googlegroups.com.
Visit this group at http://groups.google.com/group/redis-db.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages