2

My plan is to store some existing Redis keys in a hash, that would be later fetched from within a Redis Lua script and acted upon. I read that it is best practice to provide all keys that are used in a script when invoking EVAL.

My question is, is it safe to run a script that doesn't have any keys provided when running EVAL, but operates on some keys that are fetched from within the script? If not, what are the consequences and how can I avoid this shortcoming?

I mention that at the time of EVAL, there is no way of knowing what the keys in that specific hash are. I can get all the keys from the hash in a step prior to EVAL, then provide them to EVAL, but that sounds like overkill.

Kevin Christopher Henry
  • 46,175
  • 7
  • 116
  • 102
linkyndy
  • 17,038
  • 20
  • 114
  • 194

1 Answers1

7

Because of the ambiguity in the documentation this question gets asked a lot (see this and this, for example), but I'll use this occasion to try and specify the actual rule governing the use of keys in Redis scripts.

The actual rule is this: Your script must only access keys that reside on a single sever, and Redis must know what that server is so that it can route the script there.

If you're not using Redis Cluster then these conditions will always be met, since there's only one server.

If you are using Redis Cluster, then you must specify at least one key, and all keys that the script uses must be located on the same server as the specified keys.

So to answer your question: your script will work fine if you're not using Cluster. The consequences are that it won't work if you later switch to Cluster, since Redis won't know where to send the script.

It's also possible that Redis could change to enforcing the documented rule, rendering invalid all scripts that dynamically generate keys. I think that is very unlikely to happen. But specifying the keys is useful as documentation, if nothing else, so I always do it if I happen to know the keys in advance.

Kevin Christopher Henry
  • 46,175
  • 7
  • 116
  • 102
  • Thank you for your detailed answer! However, I am building a library and I am interested in making this as portable as possible. Is there a way to solve this problem? The solution I mention in my question might work, but what happens if not all the needed keys are on the same server? – linkyndy May 19 '18 at 20:59
  • 1
    @linkyndy: You can't achieve what you want with a Redis script. There's no getting around the fact that a script, with its atomicity guarantees, can only run on—and operate on keys residing in—a single server. – Kevin Christopher Henry May 19 '18 at 21:32
  • I understand. So what happens if I willingly provide to a script two keys that I **know** they reside on two distinct servers? – linkyndy May 19 '18 at 21:39
  • @linkyndy: I don't know from personal experience, but [this question](https://stackoverflow.com/q/38234507/2395796) gives an example of doing this along with the subsequent error message. – Kevin Christopher Henry May 19 '18 at 21:56
  • 1
    "So what happens if I willingly provide to a script two keys that I know they reside on two distinct servers?" <- in the cluster, you'll get a `CROSSSLOT` error. – Itamar Haber May 20 '18 at 19:59