Skip to content

Instantly share code, notes, and snippets.

@antirez
Created March 10, 2012 08:39
Show Gist options
  • Save antirez/2010867 to your computer and use it in GitHub Desktop.
Save antirez/2010867 to your computer and use it in GitHub Desktop.
Redis client-side scripting API
Hi client library users / developers, this is what I think is the best approach to expose
EVAL / EVALSHA to the final user:
redis.eval and redis.evalsha -> exposed verbatim without any intermediate layer.
redis.script(... script body ...,arguments) -> use evalsha, revert to eval if the SHA was not definied.
redis.register("foobar","...script body...") -> Creates an entry into
a table with "foobar","script body",pre_computed_SHA so that I can use
directly:
redis.foobar(mykey)
that simply does EVALSHA -> EVAL as usually, but without the need to
compute the SHA1 every time, and with a cleaner script registering
interface (that does not need to register anything at Redis level of
course, just in the client state).
KEYS vs ARGV
---
Another design issue is how to expose the fact that we can pass keys and normal arguments to the scripting engine. At least in very high level languages I recommend using a way to tell how many keys there are in redis.register() (with the ability to specify negative numbers like -2 or something like that to say, everything is a key *but* the last two arguments).
With redis.eval / evalsha there are no problems since they are exposed directly, so first argument is number of keys.
About redis.script() this is the most complex becaused it needs to be general and I think after all the best thing to do is to pass two arrays as keys and values.
This way you have three level of APIs:
redis.mycommand(key1,key2,val) -> very high level
redis.script(myscript,[key1,key2],[val]) -> general evalsha -> eval abstraction
redis.eval and redis.evalsha -> low level API exposed
@chrislovecnm
Copy link

What do you think about maintaining a version number or a data added? Just thinking about release control.

@antirez
Copy link
Author

antirez commented Mar 10, 2012

@chrislovecnm: Hello Chris, we don't want to be able to do this by design. Every instance is the same from the point of view of the client, it does not matter if it really has a script defined or not, and EVALSHA is there to make this a non issue from the point of view of performances. Managing scripts inside instances is a useless and dangerous work.

@nrk
Copy link

nrk commented Mar 10, 2012

I've been doing something similar with Predis (here is a quick'n'stupid example that leverages a very high-level abstraction) but the automatic switch between EVAL and EVALSHA is currently still missing since the state (that is, if the SHA1 has been computed or not) in our case should be kept for each connection and not globally at the client-level. I'm simply waiting to come up with a decent solution for this one.

@antirez
Copy link
Author

antirez commented Mar 10, 2012

Hi @nrk, it looks good indeed! In this case I think you should penalize client side always computing the SHA1 instead of dropping the EVALSHA -> EVAL switch, since the second is a much bigger win!

I like that you define a function that will return the number of keys in the command vector, pretty flexible.

@issackelly
Copy link

This is essentially what I'm doing on top of redispy right now. I like it a lot

@leafstorm
Copy link

One thing I'd recommend in addition to passing the number of keys, is a callback for processing the return value. It would be nice if you could either provide a function that takes the "plain" Redis return value and converts it into a native data structure, or provide the name of a Redis command whose return value is in the same format. For example, in redis-py you could pass 'smembers' to have a multi-bulk reply converted to a set, 'hgetall' to have it converted to a dictionary...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment