Redis reply error

Executing Lua in Redis

Executing Lua in Redis

Redis includes an embedded Lua 5.1 interpreter.
The interpreter runs user-defined ephemeral scripts and functions. Scripts run in a sandboxed context and can only access specific Lua packages. This page describes the packages and APIs available inside the execution’s context.

Sandbox context

The sandboxed Lua context attempts to prevent accidental misuse and reduce potential threats from the server’s environment.

Scripts should never try to access the Redis server’s underlying host systems.
That includes the file system, network, and any other attempt to perform a system call other than those supported by the API.

Scripts should operate solely on data stored in Redis and data provided as arguments to their execution.

Global variables and functions

The sandboxed Lua execution context blocks the declaration of global variables and functions.
The blocking of global variables is in place to ensure that scripts and functions don’t attempt to maintain any runtime context other than the data stored in Redis.
In the (somewhat uncommon) use case that a context needs to be maintain between executions,
you should store the context in Redis’ keyspace.

Redis will return a «Script attempted to create global variable ‘my_global_variable» error when trying to execute the following snippet:

my_global_variable = 'some value'

And similarly for the following global function declaration:

function my_global_function()
  -- Do something amazing
end

You’ll also get a similar error when your script attempts to access any global variables that are undefined in the runtime’s context:

-- The following will surely raise an error
return an_undefined_global_variable

Instead, all variable and function definitions are required to be declared as local.
To do so, you’ll need to prepend the local keyword to your declarations.
For example, the following snippet will be considered perfectly valid by Redis:

local my_local_variable = 'some value'

local function my_local_function()
  -- Do something else, but equally amazing
end

Note:
the sandbox attempts to prevent the use of globals.
Using Lua’s debugging functionality or other approaches such as altering the meta table used for implementing the globals’ protection to circumvent the sandbox isn’t hard.
However, it is difficult to circumvent the protection by accident.
If the user messes with the Lua global state, the consistency of AOF and replication can’t be guaranteed.
In other words, just don’t do it.

Imported Lua modules

Using imported Lua modules is not supported inside the sandboxed execution context.
The sandboxed execution context prevents the loading modules by disabling Lua’s require function.

The only libraries that Redis ships with and that you can use in scripts are listed under the Runtime libraries section.

Runtime globals

While the sandbox prevents users from declaring globals, the execution context is pre-populated with several of these.

The redis singleton

The redis singleton is an object instance that’s accessible from all scripts.
It provides the API to interact with Redis from scripts.
Its description follows below.

The KEYS global variable

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: no

Important:
to ensure the correct execution of scripts, both in standalone and clustered deployments, all names of keys that a function accesses must be explicitly provided as input key arguments.
The script should only access keys whose names are given as input arguments.
Scripts should never access keys with programmatically-generated names or based on the contents of data structures stored in the database.

The KEYS global variable is available only for ephemeral scripts.
It is pre-populated with all key name input arguments.

The ARGV global variable

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: no

The ARGV global variable is available only in ephemeral scripts.
It is pre-populated with all regular input arguments.

redis object

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

The Redis Lua execution context always provides a singleton instance of an object named redis.
The redis instance enables the script to interact with the Redis server that’s running it.
Following is the API provided by the redis object instance.

redis.call(command [,arg...])

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

The redis.call() function calls a given Redis command and returns its reply.
Its inputs are the command and arguments, and once called, it executes the command in Redis and returns the reply.

For example, we can call the ECHO command from a script and return its reply like so:

return redis.call('ECHO', 'Echo, echo... eco... o...')

If and when redis.call() triggers a runtime exception, the raw exception is raised back to the user as an error, automatically.
Therefore, attempting to execute the following ephemeral script will fail and generate a runtime exception because ECHO accepts exactly zero or one argument:

redis> EVAL "return redis.call('ECHO', 'Echo,', 'echo... ', 'eco... ', 'o...')" 0
(error) ERR Error running script (call to b0345693f4b77517a711221050e76d24ae60b7f7): @user_script:1: @user_script: 1: Wrong number of args calling Redis command from script

Note that the call can fail due to various reasons, see Execution under low memory conditions and Script flags

To handle Redis runtime errors use `redis.pcall() instead.

redis.pcall(command [,arg...])

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

This function enables handling runtime errors raised by the Redis server.
The redis.pcall() function behaves exactly like redis.call(), except that it:

  • Always returns a reply.
  • Never throws a runtime exception, and returns in its stead a redis.error_reply in case that a runtime exception is thrown by the server.

The following demonstrates how to use redis.pcall() to intercept and handle runtime exceptions from within the context of an ephemeral script.

local reply = redis.pcall('ECHO', unpack(ARGV))
if reply['err'] ~= nil then
  -- Handle the error sometime, but for now just log it
  redis.log(redis.LOG_WARNING, reply['err'])
  reply['err'] = 'Something is wrong, but no worries, everything is under control'
end
return reply

Evaluating this script with more than one argument will return:

redis> EVAL "..." 0 hello world
(error) Something is wrong, but no worries, everything is under control

redis.error_reply(x)

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

This is a helper function that returns an error reply.
The helper accepts a single string argument and returns a Lua table with the err field set to that string.

The outcome of the following code is that error1 and error2 are identical for all intents and purposes:

local text = 'My very special error'
local reply1 = { err = text }
local reply2 = redis.error_reply(text)

Therefore, both forms are valid as means for returning an error reply from scripts:

redis> EVAL "return { err = 'My very special table error' }" 0
(error) My very special table error
redis> EVAL "return redis.error_reply('My very special reply error')" 0
(error) My very special reply error

For returning Redis status replies refer to redis.status_reply().
Refer to the Data type conversion for returning other response types.

redis.status_reply(x)

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

This is a helper function that returns a simple string reply.
«OK» is an example of a standard Redis status reply.
The Lua API represents status replies as tables with a single field, ok, set with a simple status string.

The outcome of the following code is that status1 and status2 are identical for all intents and purposes:

local text = 'Frosty'
local status1 = { ok = text }
local status2 = redis.status_reply(text)

Therefore, both forms are valid as means for returning status replies from scripts:

redis> EVAL "return { ok = 'TICK' }" 0
TICK
redis> EVAL "return redis.status_reply('TOCK')" 0
TOCK

For returning Redis error replies refer to redis.error_reply().
Refer to the Data type conversion for returning other response types.

redis.sha1hex(x)

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

This function returns the SHA1 hexadecimal digest of its single string argument.

You can, for example, obtain the empty string’s SHA1 digest:

redis> EVAL "return redis.sha1hex('')" 0
"da39a3ee5e6b4b0d3255bfef95601890afd80709"

redis.log(level, message)

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

This function writes to the Redis server log.

It expects two input arguments: the log level and a message.
The message is a string to write to the log file.
Log level can be on of these:

  • redis.LOG_DEBUG
  • redis.LOG_VERBOSE
  • redis.LOG_NOTICE
  • redis.LOG_WARNING

These levels map to the server’s log levels.
The log only records messages equal or greater in level than the server’s loglevel configuration directive.

The following snippet:

redis.log(redis.LOG_WARNING, 'Something is terribly wrong')

will produce a line similar to the following in your server’s log:

[32343] 22 Mar 15:21:39 # Something is terribly wrong

redis.setresp(x)

  • Since version: 6.0.0
  • Available in scripts: yes
  • Available in functions: yes

This function allows the executing script to switch between Redis Serialization Protocol (RESP) versions for the replies returned by redis.call() and redis.pcall().
It expects a single numerical argument as the protocol’s version.
The default protocol version is 2, but it can be switched to version 3.

Here’s an example of switching to RESP3 replies:

Please refer to the Data type conversion for more information about type conversions.

redis.set_repl(x)

  • Since version: 3.2.0
  • Available in scripts: yes
  • Available in functions: no

Note:
this feature is only available when script effects replication is employed.
Calling it when using verbatim script replication will result in an error.
As of Redis version 2.6.0, scripts were replicated verbatim, meaning that the scripts’ source code was sent for execution by replicas and stored in the AOF.
An alternative replication mode added in version 3.2.0 allows replicating only the scripts’ effects.
As of Redis version 7.0, script replication is no longer supported, and the only replication mode available is script effects replication.

Warning:
this is an advanced feature. Misuse can cause damage by violating the contract that binds the Redis master, its replicas, and AOF contents to hold the same logical content.

This function allows a script to assert control over how its effects are propagated to replicas and the AOF afterward.
A script’s effects are the Redis write commands that it calls.

By default, all write commands that a script executes are replicated.
Sometimes, however, better control over this behavior can be helpful.
This can be the case, for example, when storing intermediate values in the master alone.

Consider a script that intersects two sets and stores the result in a temporary key with SUNIONSTORE.
It then picks five random elements (SRANDMEMBER) from the intersection and stores (SADD) them in another set.
Finally, before returning, it deletes the temporary key that stores the intersection of the two source sets.

In this case, only the new set with its five randomly-chosen elements needs to be replicated.
Replicating the SUNIONSTORE command and the `DEL’ition of the temporary key is unnecessary and wasteful.

The redis.set_repl() function instructs the server how to treat subsequent write commands in terms of replication.
It accepts a single input argument that only be one of the following:

  • redis.REPL_ALL: replicates the effects to the AOF and replicas.
  • redis.REPL_AOF: replicates the effects to the AOF alone.
  • redis.REPL_REPLICA: replicates the effects to the replicas alone.
  • redis.REPL_SLAVE: same as REPL_REPLICA, maintained for backward compatibility.
  • redis.REPL_NONE: disables effect replication entirely.

By default, the scripting engine is initialized to the redis.REPL_ALL setting when a script begins its execution.
You can call the redis.set_repl() function at any time during the script’s execution to switch between the different replication modes.

A simple example follows:

redis.replicate_commands() -- Enable effects replication in versions lower than Redis v7.0
redis.call('SET', KEYS[1], ARGV[1])
redis.set_repl(redis.REPL_NONE)
redis.call('SET', KEYS[2], ARGV[2])
redis.set_repl(redis.REPL_ALL)
redis.call('SET', KEYS[3], ARGV[3])

If you run this script by calling EVAL "..." 3 A B C 1 2 3, the result will be that only the keys A and C are created on the replicas and AOF.

redis.replicate_commands()

  • Since version: 3.2.0
  • Until version: 7.0.0
  • Available in scripts: yes
  • Available in functions: no

This function switches the script’s replication mode from verbatim replication to effects replication.
You can use it to override the default verbatim script replication mode used by Redis until version 7.0.

Note:
as of Redis v7.0, verbatim script replication is no longer supported.
The default, and only script replication mode supported, is script effects’ replication.
For more information, please refer to Replicating commands instead of scripts

redis.breakpoint()

  • Since version: 3.2.0
  • Available in scripts: yes
  • Available in functions: no

This function triggers a breakpoint when using the Redis Lua debugger](/topics/ldb).

redis.debug(x)

  • Since version: 3.2.0
  • Available in scripts: yes
  • Available in functions: no

This function prints its argument in the Redis Lua debugger console.

redis.acl_check_cmd(command [,arg...])

  • Since version: 7.0.0
  • Available in scripts: yes
  • Available in functions: yes

This function is used for checking if the current user running the script has ACL permissions to execute the given command with the given arguments.

The return value is a boolean true in case the current user has permissions to execute the command (via a call to redis.call or redis.pcall) or false in case they don’t.

The function will raise an error if the passed command or its arguments are invalid.

redis.register_function

  • Since version: 7.0.0
  • Available in scripts: no
  • Available in functions: yes

This function is only available from the context of the FUNCTION LOAD command.
When called, it registers a function to the loaded library.
The function can be called either with positional or named arguments.

positional arguments: redis.register_function(name, callback)

The first argument to redis.register_function is a Lua string representing the function name.
The second argument to redis.register_function is a Lua function.

Usage example:

redis> FUNCTION LOAD "#!lua name=mylibn redis.register_function('noop', function() end)"

Named arguments: redis.register_function{function_name=name, callback=callback, flags={flag1, flag2, ..}, description=description}

The named arguments variant accepts the following arguments:

  • function_name: the function’s name.
  • callback: the function’s callback.
  • flags: an array of strings, each a function flag (optional).
  • description: function’s description (optional).

Both function_name and callback are mandatory.

Usage example:

redis> FUNCTION LOAD "#!lua name=mylibn redis.register_function{function_name='noop', callback=function() end, flags={ 'no-writes' }, description='Does nothing'}"

Script flags

Important:
Use script flags with care, which may negatively impact if misused.
Note that the default for Eval scripts are different than the default for functions that are mentioned below, see Eval Flags

When you register a function or load an Eval script, the server does not know how it accesses the database.
By default, Redis assumes that all scripts read and write data.
This results in the following behavior:

  1. They can read and write data.
  2. They can run in cluster mode, and are not able to run commands accessing keys of different hash slots.
  3. Execution against a stale replica is denied to avoid inconsistent reads.
  4. Execution under low memory is denied to avoid exceeding the configured threshold.

You can use the following flags and instruct the server to treat the scripts’ execution differently:

  • no-writes: this flag indicates that the script only reads data but never writes.

    By default, Redis will deny the execution of flagged scripts (Functions and Eval scripts with shebang) against read-only replicas, as they may attempt to perform writes.
    Similarly, the server will not allow calling scripts with FCALL_RO / EVAL_RO.
    Lastly, when data persistence is at risk due to a disk error, execution is blocked as well.

    Using this flag allows executing the script:

    1. With FCALL_RO / EVAL_RO
    2. On read-only replicas.
    3. Even if there’s a disk error (Redis is unable to persist so it rejects writes).
    4. When over the memory limit since it implies the script doesn’t increase memory consumption (see allow-oom below)

    However, note that the server will return an error if the script attempts to call a write command.
    Also note that currently PUBLISH, SPUBLISH and PFCOUNT are also considered write commands in scripts, because they could attempt to propagate commands to replicas and AOF file.

    For more information please refer to Read-only scripts

  • allow-oom: use this flag to allow a script to execute when the server is out of memory (OOM).

    Unless used, Redis will deny the execution of flagged scripts (Functions and Eval scripts with shebang) when in an OOM state.
    Furthermore, when you use this flag, the script can call any Redis command, including commands that aren’t usually allowed in this state.
    Specifying no-writes or using FCALL_RO / EVAL_RO also implies the script can run in OOM state (without specifying allow-oom)

  • allow-stale: a flag that enables running the flagged scripts (Functions and Eval scripts with shebang) against a stale replica when the replica-serve-stale-data config is set to no .

    Redis can be set to prevent data consistency problems from using old data by having stale replicas return a runtime error.
    For scripts that do not access the data, this flag can be set to allow stale Redis replicas to run the script.
    Note however that the script will still be unable to execute any command that accesses stale data.

  • no-cluster: the flag causes the script to return an error in Redis cluster mode.

    Redis allows scripts to be executed both in standalone and cluster modes.
    Setting this flag prevents executing the script against nodes in the cluster.

  • allow-cross-slot-keys: The flag that allows a script to access keys from multiple slots.

    Redis typically prevents any single command from accessing keys that hash to multiple slots.
    This flag allows scripts to break this rule and access keys within the script that access multiple slots.
    Declared keys to the script are still always required to hash to a single slot.
    Accessing keys from multiple slots is discouraged as applications should be designed to only access keys from a single slot at a time, allowing slots to move between Redis servers.

    This flag has no effect when cluster mode is disabled.

Please refer to Function Flags and Eval Flags for a detailed example.

redis.REDIS_VERSION

  • Since version: 7.0.0
  • Available in scripts: yes
  • Available in functions: yes

Returns the current Redis server version as a Lua string.
The reply’s format is MM.mm.PP, where:

  • MM: is the major version.
  • mm: is the minor version.
  • PP: is the patch level.

redis.REDIS_VERSION_NUM

  • Since version: 7.0.0
  • Available in scripts: yes
  • Available in functions: yes

Returns the current Redis server version as a number.
The reply is a hexadecimal value structured as 0x00MMmmPP, where:

  • MM: is the major version.
  • mm: is the minor version.
  • PP: is the patch level.

Data type conversion

Unless a runtime exception is raised, redis.call() and redis.pcall() return the reply from the executed command to the Lua script.
Redis’ replies from these functions are converted automatically into Lua’s native data types.

Similarly, when a Lua script returns a reply with the return keyword,
that reply is automatically converted to Redis’ protocol.

Put differently; there’s a one-to-one mapping between Redis’ replies and Lua’s data types and a one-to-one mapping between Lua’s data types and the Redis Protocol data types.
The underlying design is such that if a Redis type is converted into a Lua type and converted back into a Redis type, the result is the same as the initial value.

Type conversion from Redis protocol replies (i.e., the replies from redis.call() and redis.pcall() to Lua data types depends on the Redis Serialization Protocol version used by the script.
The default protocol version during script executions is RESP2.
The script may switch the replies’ protocol versions by calling the redis.setresp() function.

Type conversion from a script’s returned Lua data type depends on the user’s choice of protocol (see the HELLO command).

The following sections describe the type conversion rules between Lua and Redis per the protocol’s version.

RESP2 to Lua type conversion

The following type conversion rules apply to the execution’s context by default as well as after calling redis.setresp(2):

  • RESP2 integer reply -> Lua number
  • RESP2 bulk string reply -> Lua string
  • RESP2 array reply -> Lua table (may have other Redis data types nested)
  • RESP2 status reply -> Lua table with a single ok field containing the status string
  • RESP2 error reply -> Lua table with a single err field containing the error string
  • RESP2 null bulk reply and null multi bulk reply -> Lua false boolean type

Lua to RESP2 type conversion

The following type conversion rules apply by default as well as after the user had called HELLO 2:

  • Lua number -> RESP2 integer reply (the number is converted into an integer)
  • Lua string -> RESP bulk string reply
  • Lua table (indexed, non-associative array) -> RESP2 array reply (truncated at the first Lua nil value encountered in the table, if any)
  • Lua table with a single ok field -> RESP2 status reply
  • Lua table with a single err field -> RESP2 error reply
  • Lua boolean false -> RESP2 null bulk reply

There is an additional Lua-to-Redis conversion rule that has no corresponding Redis-to-Lua conversion rule:

  • Lua Boolean true -> RESP2 integer reply with value of 1.

There are three additional rules to note about converting Lua to Redis data types:

  • Lua has a single numerical type, Lua numbers.
    There is no distinction between integers and floats.
    So we always convert Lua numbers into integer replies, removing the decimal part of the number, if any.
    If you want to return a Lua float, it should be returned as a string,
    exactly like Redis itself does (see, for instance, the ZSCORE command).
  • There’s no simple way to have nils inside Lua arrays due
    to Lua’s table semantics.
    Therefore, when Redis converts a Lua array to RESP, the conversion stops when it encounters a Lua nil value.
  • When a Lua table is an associative array that contains keys and their respective values, the converted Redis reply will not include them.

Lua to RESP2 type conversion examples:

redis> EVAL "return 10" 0
(integer) 10

redis> EVAL "return { 1, 2, { 3, 'Hello World!' } }" 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 3
   1) "Hello World!"

redis> EVAL "return redis.call('get','foo')" 0
"bar"

The last example demonstrates receiving and returning the exact return value of redis.call() (or redis.pcall()) in Lua as it would be returned if the command had been called directly.

The following example shows how floats and arrays that cont nils and keys are handled:

redis> EVAL "return { 1, 2, 3.3333, somekey = 'somevalue', 'foo', nil , 'bar' }" 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) "foo"

As you can see, the float value of 3.333 gets converted to an integer 3, the somekey key and its value are omitted, and the string «bar» isn’t returned as there is a nil value that precedes it.

RESP3 to Lua type conversion

RESP3 is a newer version of the Redis Serialization Protocol.
It is available as an opt-in choice as of Redis v6.0.

An executing script may call the redis.setresp function during its execution and switch the protocol version that’s used for returning replies from Redis’ commands (that can be invoked via redis.call() or redis.pcall()).

Once Redis’ replies are in RESP3 protocol, all of the RESP2 to Lua conversion rules apply, with the following additions:

  • RESP3 map reply -> Lua table with a single map field containing a Lua table representing the fields and values of the map.
  • RESP set reply -> Lua table with a single set field containing a Lua table representing the elements of the set as fields, each with the Lua Boolean value of true.
  • RESP3 null -> Lua nil.
  • RESP3 true reply -> Lua true boolean value.
  • RESP3 false reply -> Lua false boolean value.
  • RESP3 double reply -> Lua table with a single score field containing a Lua number representing the double value.
  • RESP3 big number reply -> Lua table with a single big_number field containing a Lua string representing the big number value.
  • Redis verbatim string reply -> Lua table with a single verbatim_string field containing a Lua table with two fields, string and format, representing the verbatim string and its format, respectively.

Note:
the RESP3 big number and verbatim strings replies are only supported as of Redis v7.0 and greater.
Also, presently, RESP3’s attributes, streamed strings and streamed aggregate data types are not supported by the Redis Lua API.

Lua to RESP3 type conversion

Regardless of the script’s choice of protocol version set for replies with the [redis.setresp() function] when it calls redis.call() or redis.pcall(), the user may opt-in to using RESP3 (with the HELLO 3 command) for the connection.
Although the default protocol for incoming client connections is RESP2, the script should honor the user’s preference and return adequately-typed RESP3 replies, so the following rules apply on top of those specified in the Lua to RESP2 type conversion section when that is the case.

  • Lua Boolean -> RESP3 Boolean reply (note that this is a change compared to the RESP2, in which returning a Boolean Lua true returned the number 1 to the Redis client, and returning a false used to return a null.
  • Lua table with a single map field set to an associative Lua table -> RESP3 map reply.
  • Lua table with a single _set field set to an associative Lua table -> RESP3 set reply. Values can be set to anything and are discarded anyway.
  • Lua table with a single double field to an associative Lua table -> RESP3 double reply.
  • Lua nil -> RESP3 null.

However, if the connection is set use the RESP2 protocol, and even if the script replies with RESP3-typed responses, Redis will automatically perform a RESP3 to RESP2 conversion of the reply as is the case for regular commands.
That means, for example, that returning the RESP3 map type to a RESP2 connection will result in the repy being converted to a flat RESP2 array that consists of alternating field names and their values, rather than a RESP3 map.

Additional notes about scripting

Using SELECT inside scripts

You can call the SELECT command from your Lua scripts, like you can with any normal client connection.
However, one subtle aspect of the behavior changed between Redis versions 2.8.11 and 2.8.12.
Prior to Redis version 2.8.12, the database selected by the Lua script was set as the current database for the client connection that had called it.
As of Redis version 2.8.12, the database selected by the Lua script only affects the execution context of the script, and does not modify the database that’s selected by the client calling the script.
This semantic change between patch level releases was required since the old behavior was inherently incompatible with Redis’ replication and introduced bugs.

Runtime libraries

The Redis Lua runtime context always comes with several pre-imported libraries.

The following standard Lua libraries are available to use:

  • The String Manipulation (string) library
  • The Table Manipulation (table) library
  • The Mathematical Functions (math) library

In addition, the following external libraries are loaded and accessible to scripts:

  • The struct library
  • The cjson library
  • The cmsgpack library
  • The bitop library

struct library

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

struct is a library for packing and unpacking C-like structures in Lua.
It provides the following functions:

  • struct.pack()
  • struct.unpack()
  • struct.size()

All of struct‘s functions expect their first argument to be a format string.

struct formats

The following are valid format strings for struct‘s functions:

  • >: big endian
  • <: little endian
  • ![num]: alignment
  • x: padding
  • b/B: signed/unsigned byte
  • h/H: signed/unsigned short
  • l/L: signed/unsigned long
  • T: size_t
  • i/In: signed/unsigned integer with size n (defaults to the size of int)
  • cn: sequence of n chars (from/to a string); when packing, n == 0 means the
    whole string; when unpacking, n == 0 means use the previously read number as
    the string’s length.
  • s: zero-terminated string
  • f: float
  • d: double
  • (space): ignored

struct.pack(x)

This function returns a struct-encoded string from values.
It accepts a struct format string as its first argument, followed by the values that are to be encoded.

Usage example:

redis> EVAL "return struct.pack('HH', 1, 2)" 0
"x01x00x02x00"

struct.unpack(x)

This function returns the decoded values from a struct.
It accepts a struct format string as its first argument, followed by encoded struct’s string.

Usage example:

redis> EVAL "return { struct.unpack('HH', ARGV[1]) }" 0 "x01x00x02x00"
1) (integer) 1
2) (integer) 2
3) (integer) 5

struct.size(x)

This function returns the size, in bytes, of a struct.
It accepts a struct format string as its only argument.

Usage example:

redis> EVAL "return struct.size('HH')" 0
(integer) 4

cjson library

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

The cjson library provides fast JSON encoding and decoding from Lua.
It provides these functions.

cjson.encode(x)

This function returns a JSON-encoded string for the Lua data type provided as its argument.

Usage example:

redis> EVAL "return cjson.encode({ ['foo'] = 'bar' })" 0
"{"foo":"bar"}"

cjson.decode(x)

This function returns a Lua data type from the JSON-encoded string provided as its argument.

Usage example:

redis> EVAL "return cjson.decode(ARGV[1])['foo']" 0 '{"foo":"bar"}'
"bar"

cmsgpack library

  • Since version: 2.6.0
  • Available in scripts: yes
  • Available in functions: yes

The cmsgpack library provides fast MessagePack encoding and decoding from Lua.
It provides these functions.

cmsgpack.pack(x)

This function returns the packed string encoding of the Lua data type it is given as an argument.

Usage example:

redis> EVAL "return cmsgpack.pack({'foo', 'bar', 'baz'})" 0
"x93xa3fooxa3barxa3baz"

cmsgpack.unpack(x)

This function returns the unpacked values from decoding its input string argument.

Usage example:

redis> EVAL "return cmsgpack.unpack(ARGV[1])" 0 "x93xa3fooxa3barxa3baz"
1) "foo"
2) "bar"
3) "baz"

bit library

  • Since version: 2.8.18
  • Available in scripts: yes
  • Available in functions: yes

The bit library provides bitwise operations on numbers.
Its documentation resides at Lua BitOp documentation
It provides the following functions.

bit.tobit(x)

Normalizes a number to the numeric range for bit operations and returns it.

Usage example:

redis> EVAL 'return bit.tobit(1)' 0
(integer) 1

bit.tohex(x [,n])

Converts its first argument to a hex string. The number of hex digits is given by the absolute value of the optional second argument.

Usage example:

redis> EVAL 'return bit.tohex(422342)' 0
"000671c6"

bit.bnot(x)

Returns the bitwise not of its argument.

bit.bnot(x) bit.bor(x1 [,x2...]), bit.band(x1 [,x2...]) and bit.bxor(x1 [,x2...])

Returns either the bitwise or, bitwise and, or bitwise xor of all of its arguments.
Note that more than two arguments are allowed.

Usage example:

redis> EVAL 'return bit.bor(1,2,4,8,16,32,64,128)' 0
(integer) 255

bit.lshift(x, n), bit.rshift(x, n) and bit.arshift(x, n)

Returns either the bitwise logical left-shift, bitwise logical right-shift, or bitwise arithmetic right-shift of its first argument by the number of bits given by the second argument.

bit.rol(x, n) and bit.ror(x, n)

Returns either the bitwise left rotation, or bitwise right rotation of its first argument by the number of bits given by the second argument.
Bits shifted out on one side are shifted back in on the other side.

bit.bswap(x)

Swaps the bytes of its argument and returns it.
This can be used to convert little-endian 32-bit numbers to big-endian 32-bit numbers and vice versa.

HIREDIS

Hiredis is a minimalistic C client library for the Redis database.

It is minimalistic because it just adds minimal support for the protocol, but
at the same time it uses an high level printf-alike API in order to make it
much higher level than otherwise suggested by its minimal code base and the
lack of explicit bindings for every Redis command.

Apart from supporting sending commands and receiving replies, it comes with
a reply parser that is decoupled from the I/O layer. It
is a stream parser designed for easy reusability, which can for instance be used
in higher level language bindings for efficient reply parsing.

Hiredis only supports the binary-safe Redis protocol, so you can use it with any
Redis version >= 1.2.0.

The library comes with multiple APIs. There is the
synchronous API, the asynchronous API and the reply parsing API.

UPGRADING

Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
code using hiredis should not be a big pain. The key thing to keep in mind when
upgrading is that hiredis >= 0.9.0 uses a redisContext* to keep state, in contrast to
the stateless 0.0.1 that only has a file descriptor to work with.

Synchronous API

To consume the synchronous API, there are only a few function calls that need to be introduced:

redisContext *redisConnect(const char *ip, int port);
void *redisCommand(redisContext *c, const char *format, ...);
void freeReplyObject(void *reply);

Connecting

The function redisConnect is used to create a so-called redisContext. The
context is where Hiredis holds state for a connection. The redisContext
struct has an integer err field that is non-zero when an the connection is in
an error state. The field errstr will contain a string with a description of
the error. More information on errors can be found in the Errors section.
After trying to connect to Redis using redisConnect you should
check the err field to see if establishing the connection was successful:

redisContext *c = redisConnect("127.0.0.1", 6379);
if (c->err) {
    printf("Error: %sn", c->errstr);
    // handle error
}

Sending commands

There are several ways to issue commands to Redis. The first that will be introduced is
redisCommand. This function takes a format similar to printf. In the simplest form,
it is used like this:

reply = redisCommand(context, "SET foo bar");

The specifier %s interpolates a string in the command, and uses strlen to
determine the length of the string:

reply = redisCommand(context, "SET foo %s", value);

When you need to pass binary safe strings in a command, the %b specifier can be
used. Together with a pointer to the string, it requires a size_t length argument
of the string:

reply = redisCommand(context, "SET foo %b", value, valuelen);

Internally, Hiredis splits the command in different arguments and will
convert it to the protocol used to communicate with Redis.
One or more spaces separates arguments, so you can use the specifiers
anywhere in an argument:

reply = redisCommand("SET key:%s %s", myid, value);

Using replies

The return value of redisCommand holds a reply when the command was
successfully executed. When an error occurs, the return value is NULL and
the err field in the context will be set (see section on Errors).
Once an error is returned the context cannot be reused and you should set up
a new connection.

The standard replies that redisCommand are of the type redisReply. The
type field in the redisReply should be used to test what kind of reply
was received:

  • REDIS_REPLY_STATUS:

    • The command replied with a status reply. The status string can be accessed using reply->str.
      The length of this string can be accessed using reply->len.
  • REDIS_REPLY_ERROR:

    • The command replied with an error. The error string can be accessed identical to REDIS_REPLY_STATUS.
  • REDIS_REPLY_INTEGER:

    • The command replied with an integer. The integer value can be accessed using the
      reply->integer field of type long long.
  • REDIS_REPLY_NIL:

    • The command replied with a nil object. There is no data to access.
  • REDIS_REPLY_STRING:

    • A bulk (string) reply. The value of the reply can be accessed using reply->str.
      The length of this string can be accessed using reply->len.
  • REDIS_REPLY_ARRAY:

    • A multi bulk reply. The number of elements in the multi bulk reply is stored in
      reply->elements. Every element in the multi bulk reply is a redisReply object as well
      and can be accessed via reply->elements[..index..].
      Redis may reply with nested arrays but this is fully supported.

Replies should be freed using the freeReplyObject() function.
Note that this function will take care of freeing sub-replies objects
contained in arrays and nested arrays, so there is no need for the user to
free the sub replies (it is actually harmful and will corrupt the memory).

Cleaning up

To disconnect and free the context the following function can be used:

void redisFree(redisContext *c);

This function immediately closes the socket and then free’s the allocations done in
creating the context.

Sending commands (cont’d)

Together with redisCommand, the function redisCommandArgv can be used to issue commands.
It has the following prototype:

void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

It takes the number of arguments argc, an array of strings argv and the lengths of the
arguments argvlen. For convenience, argvlen may be set to NULL and the function will
use strlen(3) on every argument to determine its length. Obviously, when any of the arguments
need to be binary safe, the entire array of lengths argvlen should be provided.

The return value has the same semantic as redisCommand.

Pipelining

To explain how Hiredis supports pipelining in a blocking connection, there needs to be
understanding of the internal execution flow.

When any of the functions in the redisCommand family is called, Hiredis first formats the
command according to the Redis protocol. The formatted command is then put in the output buffer
of the context. This output buffer is dynamic, so it can hold any number of commands.
After the command is put in the output buffer, redisGetReply is called. This function has the
following two execution paths:

  1. The input buffer is non-empty:
    • Try to parse a single reply from the input buffer and return it
    • If no reply could be parsed, continue at 2
  2. The input buffer is empty:
    • Write the entire output buffer to the socket
    • Read from the socket until a single reply could be parsed

The function redisGetReply is exported as part of the Hiredis API and can be used when a reply
is expected on the socket. To pipeline commands, the only things that needs to be done is
filling up the output buffer. For this cause, two commands can be used that are identical
to the redisCommand family, apart from not returning a reply:

void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

After calling either function one or more times, redisGetReply can be used to receive the
subsequent replies. The return value for this function is either REDIS_OK or REDIS_ERR, where
the latter means an error occurred while reading a reply. Just as with the other commands,
the err field in the context can be used to find out what the cause of this error is.

The following examples shows a simple pipeline (resulting in only a single call to write(2) and
a single call to write(2)):

redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
redisGetReply(context,&reply); // reply for SET
freeReplyObject(reply);
redisGetReply(context,&reply); // reply for GET
freeReplyObject(reply);

This API can also be used to implement a blocking subscriber:

reply = redisCommand(context,"SUBSCRIBE foo");
freeReplyObject(reply);
while(redisGetReply(context,&reply) == REDIS_OK) {
    // consume message
    freeReplyObject(reply);
}

Errors

When a function call is not successful, depending on the function either NULL or REDIS_ERR is
returned. The err field inside the context will be non-zero and set to one of the
following constants:

  • REDIS_ERR_IO:
    There was an I/O error while creating the connection, trying to write
    to the socket or read from the socket. If you included errno.h in your
    application, you can use the global errno variable to find out what is
    wrong.

  • REDIS_ERR_EOF:
    The server closed the connection which resulted in an empty read.

  • REDIS_ERR_PROTOCOL:
    There was an error while parsing the protocol.

  • REDIS_ERR_OTHER:
    Any other error. Currently, it is only used when a specified hostname to connect
    to cannot be resolved.

In every case, the errstr field in the context will be set to hold a string representation
of the error.

Asynchronous API

Hiredis comes with an asynchronous API that works easily with any event library.
Examples are bundled that show using Hiredis with libev
and libevent.

Connecting

The function redisAsyncConnect can be used to establish a non-blocking connection to
Redis. It returns a pointer to the newly created redisAsyncContext struct. The err field
should be checked after creation to see if there were errors creating the connection.
Because the connection that will be created is non-blocking, the kernel is not able to
instantly return if the specified host and port is able to accept a connection.

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
    printf("Error: %sn", c->errstr);
    // handle error
}

The asynchronous context can hold a disconnect callback function that is called when the
connection is disconnected (either because of an error or per user request). This function should
have the following prototype:

void(const redisAsyncContext *c, int status);

On a disconnect, the status argument is set to REDIS_OK when disconnection was initiated by the
user, or REDIS_ERR when the disconnection was caused by an error. When it is REDIS_ERR, the err
field in the context can be accessed to find out the cause of the error.

The context object is always free’d after the disconnect callback fired. When a reconnect is needed,
the disconnect callback is a good point to do so.

Setting the disconnect callback can only be done once per context. For subsequent calls it will
return REDIS_ERR. The function to set the disconnect callback has the following prototype:

int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);

Sending commands and their callbacks

In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
Therefore, unlike the synchronous API, there is only a single way to send commands.
Because commands are sent to Redis asynchronously, issuing a command requires a callback function
that is called when the reply is received. Reply callbacks should have the following prototype:

void(redisAsyncContext *c, void *reply, void *privdata);

The privdata argument can be used to curry arbitrary data to the callback from the point where
the command is initially queued for execution.

The functions that can be used to issue commands in an asynchronous context are:

int redisAsyncCommand(
  redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
  const char *format, ...);
int redisAsyncCommandArgv(
  redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
  int argc, const char **argv, const size_t *argvlen);

Both functions work like their blocking counterparts. The return value is REDIS_OK when the command
was successfully added to the output buffer and REDIS_ERR otherwise. Example: when the connection
is being disconnected per user-request, no new commands may be added to the output buffer and REDIS_ERR is
returned on calls to the redisAsyncCommand family.

If the reply for a command with a NULL callback is read, it is immediately free’d. When the callback
for a command is non-NULL, it is responsible for cleaning up the reply.

All pending callbacks are called with a NULL reply when the context encountered an error.

Disconnecting

An asynchronous connection can be terminated using:

void redisAsyncDisconnect(redisAsyncContext *ac);

When this function is called, the connection is not immediately terminated. Instead, new
commands are no longer accepted and the connection is only terminated when all pending commands
have been written to the socket, their respective replies have been read and their respective
callbacks have been executed. After this, the disconnection callback is executed with the
REDIS_OK status and the context object is free’d.

Hooking it up to event library X

There are a few hooks that need to be set on the context object after it is created.
See the adapters/ directory for bindings to libev and libevent.

Reply parsing API

To be done.

AUTHORS

Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.

*Introduction to EVAL

EVAL and EVALSHA are used to evaluate scripts using the Lua interpreter
built into Redis starting from version 2.6.0.

The first argument of EVAL is a Lua 5.1 script.
The script does not need to define a Lua function (and should not).
It is just a Lua program that will run in the context of the Redis server.

The second argument of EVAL is the number of arguments that follows the script
(starting from the third argument) that represent Redis key names.
This arguments can be accessed by Lua using the KEYS global variable in the
form of a one-based array (so KEYS[1], KEYS[2], …).

All the additional arguments should not represent key names and can be accessed
by Lua using the ARGV global variable, very similarly to what happens with
keys (so ARGV[1], ARGV[2], …).

The following example should clarify what stated above:

> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"

Note: as you can see Lua arrays are returned as Redis multi bulk replies, that
is a Redis return type that your client library will likely convert into an
Array type in your programming language.

It is possible to call Redis commands from a Lua script using two different Lua
functions:

  • redis.call()
  • redis.pcall()

redis.call() is similar to redis.pcall(), the only difference is that if a
Redis command call will result in an error, redis.call() will raise a Lua
error that in turn will force EVAL to return an error to the command caller,
while redis.pcall will trap the error and return a Lua table representing the
error.

The arguments of the redis.call() and redis.pcall() functions are all
the arguments of a well formed Redis command:

> eval "return redis.call('set','foo','bar')" 0
OK

The above script sets the key foo to the string bar.
However it violates the EVAL command semantics as all the keys that the script
uses should be passed using the KEYS array:

> eval "return redis.call('set',KEYS[1],'bar')" 1 foo
OK

All Redis commands must be analyzed before execution to determine which
keys the command will operate on. In order for this to be true for EVAL, keys must be passed explicitly.
This is useful in many ways, but especially to make sure Redis Cluster
can forward your request to the appropriate cluster node.

Note this rule is not enforced in order to provide the user with
opportunities to abuse the Redis single instance configuration, at the cost of
writing scripts not compatible with Redis Cluster.

Lua scripts can return a value that is converted from the Lua type to the Redis
protocol using a set of conversion rules.

*Conversion between Lua and Redis data types

Redis return values are converted into Lua data types when Lua calls a Redis
command using call() or pcall().
Similarly Lua data types are converted into the Redis protocol when a Lua script
returns a value, so that scripts can control what EVAL will return to the
client.

This conversion between data types is designed in a way that if a Redis type is
converted into a Lua type, and then the result is converted back into a Redis
type, the result is the same as the initial value.

In other words there is a one-to-one conversion between Lua and Redis types.
The following table shows you all the conversions rules:

Redis to Lua conversion table.

  • Redis integer reply -> Lua number
  • Redis bulk reply -> Lua string
  • Redis multi bulk reply -> Lua table (may have other Redis data types nested)
  • Redis status reply -> Lua table with a single ok field containing the status
  • Redis error reply -> Lua table with a single err field containing the error
  • Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type

Lua to Redis conversion table.

  • Lua number -> Redis integer reply (the number is converted into an integer)
  • Lua string -> Redis bulk reply
  • Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside the Lua array if any)
  • Lua table with a single ok field -> Redis status reply
  • Lua table with a single err field -> Redis error reply
  • Lua boolean false -> Redis Nil bulk reply.

There is an additional Lua-to-Redis conversion rule that has no corresponding
Redis to Lua conversion rule:

  • Lua boolean true -> Redis integer reply with value of 1.

Also there are two important rules to note:

  • Lua has a single numerical type, Lua numbers. There is no distinction between integers and floats. So we always convert Lua numbers into integer replies, removing the decimal part of the number if any. If you want to return a float from Lua you should return it as a string, exactly like Redis itself does (see for instance the ZSCORE command).
  • There is no simple way to have nils inside Lua arrays, this is a result of Lua table semantics, so when Redis converts a Lua array into Redis protocol the conversion is stopped if a nil is encountered.

Here are a few conversion examples:

> eval "return 10" 0
(integer) 10

> eval "return {1,2,{3,'Hello World!'}}" 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 3
   2) "Hello World!"

> eval "return redis.call('get','foo')" 0
"bar"

The last example shows how it is possible to receive the exact return value of
redis.call() or redis.pcall() from Lua that would be returned if the command
was called directly.

In the following example we can see how floats and arrays with nils are handled:

> eval "return {1,2,3.3333,'foo',nil,'bar'}" 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) "foo"

As you can see 3.333 is converted into 3, and the bar string is never returned as there is a nil before.

*Helper functions to return Redis types

There are two helper functions to return Redis types from Lua.

  • redis.error_reply(error_string) returns an error reply. This function simply returns a single field table with the err field set to the specified string for you.
  • redis.status_reply(status_string) returns a status reply. This function simply returns a single field table with the ok field set to the specified string for you.

There is no difference between using the helper functions or directly returning the table with the specified format, so the following two forms are equivalent:

return {err="My Error"}
return redis.error_reply("My Error")

*Atomicity of scripts

Redis uses the same Lua interpreter to run all the commands.
Also Redis guarantees that a script is executed in an atomic way: no other
script or Redis command will be executed while a script is being executed.
This semantic is similar to the one of MULTI / EXEC.
From the point of view of all the other clients the effects of a script are
either still not visible or already completed.

However this also means that executing slow scripts is not a good idea.
It is not hard to create fast scripts, as the script overhead is very low, but
if you are going to use slow scripts you should be aware that while the script
is running no other client can execute commands.

*Error handling

As already stated, calls to redis.call() resulting in a Redis command error
will stop the execution of the script and return an error, in a way that
makes it obvious that the error was generated by a script:

> del foo
(integer) 1
> lpush foo a
(integer) 1
> eval "return redis.call('get','foo')" 0
(error) ERR Error running script (call to f_6b1bf486c81ceb7edf3c093f4c48582e38c0e791): ERR Operation against a key holding the wrong kind of value

Using redis.pcall() no error is raised, but an error object is
returned in the format specified above (as a Lua table with an err field).
The script can pass the exact error to the user by returning the error object
returned by redis.pcall().

*Bandwidth and EVALSHA

The EVAL command forces you to send the script body again and again.
Redis does not need to recompile the script every time as it uses an internal
caching mechanism, however paying the cost of the additional bandwidth may not
be optimal in many contexts.

On the other hand, defining commands using a special command or via redis.conf
would be a problem for a few reasons:

  • Different instances may have different implementations of a command.

  • Deployment is hard if we have to make sure all instances contain a
    given command, especially in a distributed environment.

  • Reading application code, the complete semantics might not be clear since the
    application calls commands defined server side.

In order to avoid these problems while avoiding the bandwidth penalty, Redis
implements the EVALSHA command.

EVALSHA works exactly like EVAL, but instead of having a script as the first
argument it has the SHA1 digest of a script.
The behavior is the following:

  • If the server still remembers a script with a matching SHA1 digest, the
    script is executed.

  • If the server does not remember a script with this SHA1 digest, a special
    error is returned telling the client to use EVAL instead.

Example:

> set foo bar
OK
> eval "return redis.call('get','foo')" 0
"bar"
> evalsha 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 0
"bar"
> evalsha ffffffffffffffffffffffffffffffffffffffff 0
(error) `NOSCRIPT` No matching script. Please use [EVAL](/commands/eval).

The client library implementation can always optimistically send EVALSHA under
the hood even when the client actually calls EVAL, in the hope the script was
already seen by the server.
If the NOSCRIPT error is returned EVAL will be used instead.

Passing keys and arguments as additional EVAL arguments is also very useful in
this context as the script string remains constant and can be efficiently cached
by Redis.

*Script cache semantics

Executed scripts are guaranteed to be in the script cache of a given execution
of a Redis instance forever. This means that if an EVAL is performed against a Redis instance all the subsequent EVALSHA calls will succeed.

The reason why scripts can be cached for long time is that it is unlikely for
a well written application to have enough different scripts to cause memory
problems. Every script is conceptually like the implementation of a new command, and even a large application will likely have just a few hundred of them.
Even if the application is modified many times and scripts will change, the
memory used is negligible.

The only way to flush the script cache is by explicitly calling the SCRIPT FLUSH command, which will completely flush the scripts cache removing all the
scripts executed so far.

This is usually needed only when the instance is going to be instantiated for
another customer or application in a cloud environment.

Also, as already mentioned, restarting a Redis instance flushes the
script cache, which is not persistent. However from the point of view of the
client there are only two ways to make sure a Redis instance was not restarted
between two different commands.

  • The connection we have with the server is persistent and was never closed so far.
  • The client explicitly checks the runid field in the INFO command in order to make sure the server was not restarted and is still the same process.

Practically speaking, for the client it is much better to simply assume that in the context of a given connection, cached scripts are guaranteed to be there
unless an administrator explicitly called the SCRIPT FLUSH command.

The fact that the user can count on Redis not removing scripts is semantically
useful in the context of pipelining.

For instance an application with a persistent connection to Redis can be sure
that if a script was sent once it is still in memory, so EVALSHA can be used
against those scripts in a pipeline without the chance of an error being
generated due to an unknown script (we’ll see this problem in detail later).

A common pattern is to call SCRIPT LOAD to load all the scripts that will
appear in a pipeline, then use EVALSHA directly inside the pipeline without
any need to check for errors resulting from the script hash not being
recognized.

*The SCRIPT command

Redis offers a SCRIPT command that can be used in order to control the scripting
subsystem.
SCRIPT currently accepts three different commands:

  • SCRIPT FLUSH

    This command is the only way to force Redis to flush the scripts cache.
    It is most useful in a cloud environment where the same instance can be
    reassigned to a different user.
    It is also useful for testing client libraries’ implementations of the
    scripting feature.

  • SCRIPT EXISTS sha1 sha2 ... shaN

    Given a list of SHA1 digests as arguments this command returns an array of
    1 or 0, where 1 means the specific SHA1 is recognized as a script already
    present in the scripting cache, while 0 means that a script with this SHA1
    was never seen before (or at least never seen after the latest SCRIPT FLUSH
    command).

  • SCRIPT LOAD script

    This command registers the specified script in the Redis script cache.
    The command is useful in all the contexts where we want to make sure that
    EVALSHA will not fail (for instance during a pipeline or MULTI/EXEC
    operation), without the need to actually execute the script.

  • SCRIPT KILL

    This command is the only way to interrupt a long-running script that reaches
    the configured maximum execution time for scripts.
    The SCRIPT KILL command can only be used with scripts that did not modify
    the dataset during their execution (since stopping a read-only script does
    not violate the scripting engine’s guaranteed atomicity).
    See the next sections for more information about long running scripts.

*Scripts as pure functions

A very important part of scripting is writing scripts that are pure functions.
Scripts executed in a Redis instance are, by default, replicated on slaves
and into the AOF file by sending the script itself — not the resulting
commands.

The reason is that sending a script to another Redis instance is often much
faster than sending the multiple commands the script generates, so if the
client is sending many scripts to the master, converting the scripts into
individual commands for the slave / AOF would result in too much bandwidth
for the replication link or the Append Only File (and also too much CPU since
dispatching a command received via network is a lot more work for Redis compared
to dispatching a command invoked by Lua scripts).

Normally replicating scripts instead of the effects of the scripts makes sense,
however not in all the cases. So starting with Redis 3.2 (currently not stable),
the scripting engine is able to, alternatively, replicate the sequence of write
commands resulting from the script execution, instead of replication the
script itself. See the next section for more information.
In this section we’ll assume that scripts are replicated by sending the whole
script. Let’s call this replication mode whole scripts replication.

The main drawback with the whole scripts replication approach is that scripts are required to have the following property:

  • The script must always evaluates the same Redis write commands with the
    same arguments given the same input data set.
    Operations performed by the script cannot depend on any hidden (non-explicit)
    information or state that may change as script execution proceeds or between
    different executions of the script, nor can it depend on any external input
    from I/O devices.

Things like using the system time, calling Redis random commands like
RANDOMKEY, or using Lua random number generator, could result into scripts
that will not always evaluate in the same way.

In order to enforce this behavior in scripts Redis does the following:

  • Lua does not export commands to access the system time or other external
    state.
  • 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).
  • Redis commands that may return elements in random order, like SMEMBERS
    (because Redis Sets are unordered) have a different behavior when called
    from Lua, and undergo a silent lexicographical sorting filter before
    returning data to Lua scripts.
    So redis.call("smembers",KEYS[1]) will always return the Set elements
    in the same order, while the same command invoked from normal clients may
    return different results even if the key contains exactly the same elements.
  • Lua pseudo random number generation functions math.random and
    math.randomseed are modified in order to always have the same seed every
    time a new script is executed.
    This means that calling math.random will always generate the same sequence
    of numbers every time a script is executed if math.randomseed is not used.

However the user is still able to write commands with random behavior using the
following simple trick.
Imagine I want to write a Redis script that will populate a list with N random
integers.

I can start with this small Ruby program:

require 'rubygems'
require 'redis'

r = Redis.new

RandomPushScript = <<EOF
    local i = tonumber(ARGV[1])
    local res
    while (i > 0) do
        res = redis.call('lpush',KEYS[1],math.random())
        i = i-1
    end
    return res
EOF

r.del(:mylist)
puts r.eval(RandomPushScript,[:mylist],[10,rand(2**32)])

Every time this script executed the resulting list will have exactly the
following elements:

> lrange mylist 0 -1
 1) "0.74509509873814"
 2) "0.87390407681181"
 3) "0.36876626981831"
 4) "0.6921941534114"
 5) "0.7857992587545"
 6) "0.57730350670279"
 7) "0.87046522734243"
 8) "0.09637165539729"
 9) "0.74990198051087"
10) "0.17082803611217"

In order to make it a pure function, but still be sure that every invocation
of the script will result in different random elements, we can simply add an
additional argument to the script that will be used in order to seed the Lua
pseudo-random number generator.
The new script is as follows:

RandomPushScript = <<EOF
    local i = tonumber(ARGV[1])
    local res
    math.randomseed(tonumber(ARGV[2]))
    while (i > 0) do
        res = redis.call('lpush',KEYS[1],math.random())
        i = i-1
    end
    return res
EOF

r.del(:mylist)
puts r.eval(RandomPushScript,1,:mylist,10,rand(2**32))

What we are doing here is sending the seed of the PRNG as one of the arguments.
This way the script output will be the same given the same arguments, but we are
changing one of the arguments in every invocation, generating the random seed
client-side.
The seed will be propagated as one of the arguments both in the replication
link and in the Append Only File, guaranteeing that the same changes will be
generated when the AOF is reloaded or when the slave processes the script.

Note: an important part of this behavior is that the PRNG that Redis implements
as math.random and math.randomseed is guaranteed to have the same output
regardless of the architecture of the system running Redis.
32-bit, 64-bit, big-endian and little-endian systems will all produce the same
output.

*Replicating commands instead of scripts

Starting with Redis 3.2 (not yet stable) it is possible to select an
alternative replication method. Instead of replication whole scripts, we
can just replicate single write commands generated by the script.
We call this script effects replication.

In this replication mode, while Lua scripts are executed, Redis collects
all the commands executed by the Lua scripting engine that actually modify
the dataset. When the script execution finishes, the sequence of commands
that the script generated are wrapped into a MULTI / EXEC transaction and
are sent to slaves and AOF.

This is useful in several ways depending on the use case:

  • When the script is slow to compute, but the effects can be summarized by
    a few write commands, it is a shame to re-compute the script on the slaves
    or when reloading the AOF. In this case to replicate just the effect of the
    script is much better.
  • When script effects replication is enabled, the controls about non
    deterministic functions are disabled. You can, for example, use the TIME
    or SRANDMEMBER commands inside your scripts freely at any place.
  • The Lua PRNG in this mode is seeded randomly at every call.

In order to enable script effects replication, you need to issue the
following Lua command before any write operated by the script:

redis.replicate_commands();

The function returns true if the script effects replication was enabled,
otherwise if the function was called after the script already called
some write command, it returns false, and normal whole script replication
is used.

*Selective replication of commands

When script effects replication is selected (see the previous section), it
is possible to have more control in the way commands are replicated to slaves
and AOF. This is a very advanced feature since a misuse can do damage by
breaking the contract that the master, slaves, and AOF, all must contain the
same logical content.

However this is a useful feature since, sometimes, we need to execute certain
commands only in the master in order to create, for example, intermediate
values.

Think at a Lua script where we perform an intersection between two sets.
Pick five random elements, and create a new set with this five random
elements. Finally we delete the temporary key representing the intersection
between the two original sets. What we want to replicate is only the creation
of the new set with the five elements. It’s not useful to also replicate the
commands creating the temporary key.

For this reason, Redis 3.2 introduces a new command that only works when
script effects replication is enabled, and is able to control the scripting
replication engine. The command is called redis.set_repl() and fails raising
an error if called when script effects replication is disabled.

The command can be called with four different arguments:

redis.set_repl(redis.REPL_ALL); -- Replicte to AOF and slaves.
redis.set_repl(redis.REPL_AOF); -- Replicte only to AOF.
redis.set_repl(redis.REPL_SLAVE); -- Replicte only to slaves.
redis.set_repl(redis.REPL_NONE); -- Don't replicate at all.

By default the scripting engine is always set to REPL_ALL. By calling
this function the user can switch on/off AOF and or slaves replication, and
turn them back later at her/his wish.

A simple example follows:

redis.replicate_commands(); -- Enable effects replication.
redis.call('set','A','1');
redis.set_repl(redis.REPL_NONE);
redis.call('set','B','2');
redis.set_repl(redis.REPL_ALL);
redis.call('set','C','3');

After running the above script, the result is that only keys A and C
will be created on slaves and AOF.

*Global variables protection

Redis scripts are not allowed to create global variables, in order to avoid
leaking data into the Lua state.
If a script needs to maintain state between calls (a pretty uncommon need) it
should use Redis keys instead.

When global variable access is attempted the script is terminated and EVAL
returns with an error:

redis 127.0.0.1:6379> eval 'a=10' 0
(error) ERR Error running script (call to f_933044db579a2f8fd45d8065f04a8d0249383e57): user_script:1: Script attempted to create global variable 'a'

Accessing a non existing global variable generates a similar error.

Using Lua debugging functionality or other approaches like altering the meta
table used to implement global protections in order to circumvent globals
protection is not hard.
However it is difficult to do it accidentally.
If the user messes with the Lua global state, the consistency of AOF and
replication is not guaranteed: don’t do it.

Note for Lua newbies: in order to avoid using global variables in your scripts
simply declare every variable you are going to use using the local keyword.

*Using SELECT inside scripts

It is possible to call SELECT inside Lua scripts like with normal clients,
However one subtle aspect of the behavior changes between Redis 2.8.11 and
Redis 2.8.12. Before the 2.8.12 release the database selected by the Lua
script was transferred to the calling script as current database.
Starting from Redis 2.8.12 the database selected by the Lua script only
affects the execution of the script itself, but does not modify the database
selected by the client calling the script.

The semantic change between patch level releases was needed since the old
behavior was inherently incompatible with the Redis replication layer and
was the cause of bugs.

*Available libraries

The Redis Lua interpreter loads the following Lua libraries:

  • base lib.
  • table lib.
  • string lib.
  • math lib.
  • struct lib.
  • cjson lib.
  • cmsgpack lib.
  • bitop lib.
  • redis.sha1hex function.
  • redis.breakpoint and redis.debug function in the context of the Redis Lua debugger.

Every Redis instance is guaranteed to have all the above libraries so you can
be sure that the environment for your Redis scripts is always the same.

struct, CJSON and cmsgpack are external libraries, all the other libraries are standard
Lua libraries.

*struct

struct is a library for packing/unpacking structures within Lua.

Valid formats:
> - big endian
< - little endian
![num] - alignment
x - pading
b/B - signed/unsigned byte
h/H - signed/unsigned short
l/L - signed/unsigned long
T   - size_t
i/In - signed/unsigned integer with size `n' (default is size of int)
cn - sequence of `n' chars (from/to a string); when packing, n==0 means
     the whole string; when unpacking, n==0 means use the previous
     read number as the string length
s - zero-terminated string
f - float
d - double
' ' - ignored

Example:

127.0.0.1:6379> eval 'return struct.pack("HH", 1, 2)' 0
"x01x00x02x00"
127.0.0.1:6379> eval 'return {struct.unpack("HH", ARGV[1])}' 0 "x01x00x02x00"
1) (integer) 1
2) (integer) 2
3) (integer) 5
127.0.0.1:6379> eval 'return struct.size("HH")' 0
(integer) 4

*CJSON

The CJSON library provides extremely fast JSON manipulation within Lua.

Example:

redis 127.0.0.1:6379> eval 'return cjson.encode({["foo"]= "bar"})' 0
"{"foo":"bar"}"
redis 127.0.0.1:6379> eval 'return cjson.decode(ARGV[1])["foo"]' 0 "{"foo":"bar"}"
"bar"

*cmsgpack

The cmsgpack library provides simple and fast MessagePack manipulation within Lua.

Example:

127.0.0.1:6379> eval 'return cmsgpack.pack({"foo", "bar", "baz"})' 0
"x93xa3fooxa3barxa3baz"
127.0.0.1:6379> eval 'return cmsgpack.unpack(ARGV[1])' 0 "x93xa3fooxa3barxa3baz"
1) "foo"
2) "bar"
3) "baz"

*bitop

The Lua Bit Operations Module adds bitwise operations on numbers.
It is available for scripting in Redis since version 2.8.18.

Example:

127.0.0.1:6379> eval 'return bit.tobit(1)' 0
(integer) 1
127.0.0.1:6379> eval 'return bit.bor(1,2,4,8,16,32,64,128)' 0
(integer) 255
127.0.0.1:6379> eval 'return bit.tohex(422342)' 0
"000671c6"

It supports several other functions:
bit.tobit, bit.tohex, bit.bnot, bit.band, bit.bor, bit.bxor,
bit.lshift, bit.rshift, bit.arshift, bit.rol, bit.ror, bit.bswap.
All available functions are documented in the Lua BitOp documentation

*redis.sha1hex

Perform the SHA1 of the input string.

Example:

127.0.0.1:6379> eval 'return redis.sha1hex(ARGV[1])' 0 "foo"
"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"

*Emitting Redis logs from scripts

It is possible to write to the Redis log file from Lua scripts using the
redis.log function.

redis.log(loglevel,message)

loglevel is one of:

  • redis.LOG_DEBUG
  • redis.LOG_VERBOSE
  • redis.LOG_NOTICE
  • redis.LOG_WARNING

They correspond directly to the normal Redis log levels.
Only logs emitted by scripting using a log level that is equal or greater than
the currently configured Redis instance log level will be emitted.

The message argument is simply a string.
Example:

redis.log(redis.LOG_WARNING,"Something is wrong with this script.")

Will generate the following:

[32343] 22 Mar 15:21:39 # Something is wrong with this script.

*Sandbox and maximum execution time

Scripts should never try to access the external system, like the file system or
any other system call.
A script should only operate on Redis data and passed arguments.

Scripts are also subject to a maximum execution time (five seconds by default).
This default timeout is huge since a script should usually run in under a
millisecond.
The limit is mostly to handle accidental infinite loops created during
development.

It is possible to modify the maximum time a script can be executed with
millisecond precision, either via redis.conf or using the CONFIG GET / CONFIG
SET command.
The configuration parameter affecting max execution time is called
lua-time-limit.

When a script reaches the timeout it is not automatically terminated by Redis
since this violates the contract Redis has with the scripting engine to ensure
that scripts are atomic.
Interrupting a script means potentially leaving the dataset with half-written
data.
For this reasons when a script executes for more than the specified time the
following happens:

  • Redis logs that a script is running too long.
  • It starts accepting commands again from other clients, but will reply with a
    BUSY error to all the clients sending normal commands.
    The only allowed commands in this status are SCRIPT KILL and SHUTDOWN
    NOSAVE
    .
  • It is possible to terminate a script that executes only read-only commands
    using the SCRIPT KILL command.
    This does not violate the scripting semantic as no data was yet written to the
    dataset by the script.
  • If the script already called write commands the only allowed command becomes
    SHUTDOWN NOSAVE that stops the server without saving the current data set on
    disk (basically the server is aborted).

*EVALSHA in the context of pipelining

Care should be taken when executing EVALSHA in the context of a pipelined
request, since even in a pipeline the order of execution of commands must be
guaranteed.
If EVALSHA will return a NOSCRIPT error the command can not be reissued
later otherwise the order of execution is violated.

The client library implementation should take one of the following approaches:

  • Always use plain EVAL when in the context of a pipeline.

  • Accumulate all the commands to send into the pipeline, then check for EVAL
    commands and use the SCRIPT EXISTS command to check if all the scripts are
    already defined.
    If not, add SCRIPT LOAD commands on top of the pipeline as required, and
    use EVALSHA for all the EVAL calls.

*Debugging Lua scripts

Starting with Redis 3.2 (currently in beta), Redis has support for native
Lua debugging. The Redis Lua debugger is a remote debugger consisting of
a server, which is Redis itself, and a client, which is by default redis-cli.

The Lua debugger is described in the Lua scripts debugging section of the Redis documentation.

Redis clients communicate with the Redis server using a protocol called RESP (REdis Serialization Protocol). While the protocol was designed specifically for Redis, it can be used for other client-server software projects.

RESP is a compromise between the following things:

  • Simple to implement.
  • Fast to parse.
  • Human readable.

RESP can serialize different data types like integers, strings, arrays. There is also a specific type for errors. Requests are sent from the client to the Redis server as arrays of strings representing the arguments of the command to execute. Redis replies with a command-specific data type.

RESP is binary-safe and does not require processing of bulk data transferred from one process to another, because it uses prefixed-length to transfer bulk data.

Note: the protocol outlined here is only used for client-server communication. Redis Cluster uses a different binary protocol in order to exchange messages between nodes.

Networking layer

A client connects to a Redis server creating a TCP connection to the port 6379.

While RESP is technically non-TCP specific, in the context of Redis the protocol is only used with TCP connections (or equivalent stream oriented connections like Unix sockets).

Request-Response model

Redis accepts commands composed of different arguments.
Once a command is received, it is processed and a reply is sent back to the client.

This is the simplest model possible, however there are two exceptions:

  • Redis supports pipelining (covered later in this document). So it is possible for clients to send multiple commands at once, and wait for replies later.
  • When a Redis client subscribes to a Pub/Sub channel, the protocol changes semantics and becomes a push protocol, that is, the client no longer requires to send commands, because the server will automatically send to the client new messages (for the channels the client is subscribed to) as soon as they are received.

Excluding the above two exceptions, the Redis protocol is a simple request-response protocol.

RESP protocol description

The RESP protocol was introduced in Redis 1.2, but it became the
standard way for talking with the Redis server in Redis 2.0.
This is the protocol you should implement in your Redis client.

RESP is actually a serialization protocol that supports the following
data types: Simple Strings, Errors, Integers, Bulk Strings and Arrays.

The way RESP is used in Redis as a request-response protocol is the
following:

  • Clients send commands to a Redis server as a RESP Array of Bulk Strings.
  • The server replies with one of the RESP types according to the command implementation.

In RESP, the type of some data depends on the first byte:

  • For Simple Strings the first byte of the reply is «+»
  • For Errors the first byte of the reply is «-«
  • For Integers the first byte of the reply is «:»
  • For Bulk Strings the first byte of the reply is «$»
  • For Arrays the first byte of the reply is «*«

Additionally RESP is able to represent a Null value using a special variation of Bulk Strings or Array as specified later.

In RESP different parts of the protocol are always terminated with «rn» (CRLF).

RESP Simple Strings

Simple Strings are encoded in the following way: a plus character, followed by a string that cannot contain a CR or LF character (no newlines are allowed), terminated by CRLF (that is «rn»).

Simple Strings are used to transmit non binary safe strings with minimal overhead. For example many Redis commands reply with just «OK» on success, that as a RESP Simple String is encoded with the following 5 bytes:

"+OKrn"

In order to send binary-safe strings, RESP Bulk Strings are used instead.

When Redis replies with a Simple String, a client library should return
to the caller a string composed of the first character after the ‘+’
up to the end of the string, excluding the final CRLF bytes.

RESP Errors

RESP has a specific data type for errors. Actually errors are exactly like
RESP Simple Strings, but the first character is a minus ‘-‘ character instead
of a plus. The real difference between Simple Strings and Errors in RESP is that
errors are treated by clients as exceptions, and the string that composes
the Error type is the error message itself.

The basic format is:

"-Error messagern"

Error replies are only sent when something wrong happens, for instance if
you try to perform an operation against the wrong data type, or if the command
does not exist and so forth. An exception should be raised by the library
client when an Error Reply is received.

The following are examples of error replies:

-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value

The first word after the «-«, up to the first space or newline, represents
the kind of error returned. This is just a convention used by Redis and is not
part of the RESP Error format.

For example, ERR is the generic error, while WRONGTYPE is a more specific
error that implies that the client tried to perform an operation against the
wrong data type. This is called an Error Prefix and is a way to allow
the client to understand the kind of error returned by the server without
to rely on the exact message given, that may change over the time.

A client implementation may return different kind of exceptions for different
errors, or may provide a generic way to trap errors by directly providing
the error name to the caller as a string.

However, such a feature should not be considered vital as it is rarely useful, and a limited client implementation may simply return a generic error condition, such as false.

RESP Integers

This type is just a CRLF terminated string representing an integer,
prefixed by a «:» byte. For example «:0rn», or «:1000rn» are integer
replies.

Many Redis commands return RESP Integers, like INCR, LLEN and LASTSAVE.

There is no special meaning for the returned integer, it is just an
incremental number for INCR, a UNIX time for LASTSAVE and so forth. However,
the returned integer is guaranteed to be in the range of a signed 64 bit
integer.

Integer replies are also extensively used in order to return true or false.
For instance commands like EXISTS or SISMEMBER will return 1 for true
and 0 for false.

Other commands like SADD, SREM and SETNX will return 1 if the operation
was actually performed, 0 otherwise.

The following commands will reply with an integer reply: SETNX, DEL,
EXISTS, INCR, INCRBY, DECR, DECRBY, DBSIZE, LASTSAVE,
RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD.

RESP Bulk Strings

Bulk Strings are used in order to represent a single binary safe
string up to 512 MB in length.

Bulk Strings are encoded in the following way:

  • A «$» byte followed by the number of bytes composing the string (a prefixed length), terminated by CRLF.
  • The actual string data.
  • A final CRLF.

So the string «foobar» is encoded as follows:

"$6rnfoobarrn"

When an empty string is just:

"$0rnrn"

RESP Bulk Strings can also be used in order to signal non-existence of a value
using a special format that is used to represent a Null value. In this special
format the length is -1, and there is no data, so a Null is represented as:

"$-1rn"

This is called a Null Bulk String.

The client library API should not return an empty string, but a nil object,
when the server replies with a Null Bulk String.
For example a Ruby library should return ‘nil’ while a C library should
return NULL (or set a special flag in the reply object), and so forth.

RESP Arrays

Clients send commands to the Redis server using RESP Arrays. Similarly
certain Redis commands returning collections of elements to the client
use RESP Arrays are reply type. An example is the LRANGE command that
returns elements of a list.

RESP Arrays are sent using the following format:

  • A * character as the first byte, followed by the number of elements in the array as a decimal number, followed by CRLF.
  • An additional RESP type for every element of the Array.

So an empty Array is just the following:

"*0rn"

While an array of two RESP Bulk Strings «foo» and «bar» is encoded as:

"*2rn$3rnfoorn$3rnbarrn"

As you can see after the *<count>CRLF part prefixing the array, the other
data types composing the array are just concatenated one after the other.
For example an Array of three integers is encoded as follows:

"*3rn:1rn:2rn:3rn"

Arrays can contain mixed types, it’s not necessary for the
elements to be of the same type. For instance, a list of four
integers and a bulk string can be encoded as the follows:

*5rn
:1rn
:2rn
:3rn
:4rn
$6rn
foobarrn

(The reply was split into multiple lines for clarity).

The first line the server sent is *5rn in order to specify that five
replies will follow. Then every reply constituting the items of the
Multi Bulk reply are transmitted.

The concept of Null Array exists as well, and is an alternative way to
specify a Null value (usually the Null Bulk String is used, but for historical
reasons we have two formats).

For instance when the BLPOP command times out, it returns a Null Array
that has a count of -1 as in the following example:

"*-1rn"

A client library API should return a null object and not an empty Array when
Redis replies with a Null Array. This is necessary to distinguish
between an empty list and a different condition (for instance the timeout
condition of the BLPOP command).

Arrays of arrays are possible in RESP. For example an array of two arrays
is encoded as follows:

*2rn
*3rn
:1rn
:2rn
:3rn
*2rn
+Foorn
-Barrn

(The format was split into multiple lines to make it easier to read).

The above RESP data type encodes a two elements Array consisting of an Array that contains three Integers 1, 2, 3 and an array of a Simple String and an Error.

Null elements in Arrays

Single elements of an Array may be Null. This is used in Redis replies in
order to signal that this elements are missing and not empty strings. This
can happen with the SORT command when used with the GET pattern option
when the specified key is missing. Example of an Array reply containing a
Null element:

*3rn
$3rn
foorn
$-1rn
$3rn
barrn

The second element is a Null. The client library should return something
like this:

["foo",nil,"bar"]

Note that this is not an exception to what said in the previous sections, but
just an example to further specify the protocol.

Sending commands to a Redis Server

Now that you are familiar with the RESP serialization format, writing an
implementation of a Redis client library will be easy. We can further specify
how the interaction between the client and the server works:

  • A client sends to the Redis server a RESP Array consisting of just Bulk Strings.
  • A Redis server replies to clients sending any valid RESP data type as reply.

So for example a typical interaction could be the following.

The client sends the command LLEN mylist in order to get the length of the list stored at key mylist, and the server replies with an Integer reply as in the following example (C: is the client, S: the server).

C: *2rn
C: $4rn
C: LLENrn
C: $6rn
C: mylistrn

S: :48293rn

As usually we separate different parts of the protocol with newlines for simplicity, but the actual interaction is the client sending *2rn$4rnLLENrn$6rnmylistrn as a whole.

Multiple commands and pipelining

A client can use the same connection in order to issue multiple commands.
Pipelining is supported so multiple commands can be sent with a single
write operation by the client, without the need to read the server reply
of the previous command before issuing the next one.
All the replies can be read at the end.

For more information please check our page about Pipelining.

Inline Commands

Sometimes you have only telnet in your hands and you need to send a command
to the Redis server. While the Redis protocol is simple to implement it is
not ideal to use in interactive sessions, and redis-cli may not always be
available. For this reason Redis also accepts commands in a special way that
is designed for humans, and is called the inline command format.

The following is an example of a server/client chat using an inline command
(the server chat starts with S:, the client chat with C:)

C: PING
S: +PONG

The following is another example of an inline command returning an integer:

C: EXISTS somekey
S: :0

Basically you simply write space-separated arguments in a telnet session.
Since no command starts with * that is instead used in the unified request
protocol, Redis is able to detect this condition and parse your command.

High performance parser for the Redis protocol

While the Redis protocol is very human readable and easy to implement it can
be implemented with a performance similar to that of a binary protocol.

RESP uses prefixed lengths to transfer bulk data, so there is
never need to scan the payload for special characters like it happens for
instance with JSON, nor to quote the payload that needs to be sent to the
server.

The Bulk and Multi Bulk lengths can be processed with code that performs
a single operation per character while at the same time scanning for the
CR character, like the following C code:

#include <stdio.h>

int main(void) {
    unsigned char *p = "$123rn";
    int len = 0;

    p++;
    while(*p != 'r') {
        len = (len*10)+(*p - '0');
        p++;
    }

    /* Now p points at 'r', and the len is in bulk_len. */
    printf("%dn", len);
    return 0;
}

After the first CR is identified, it can be skipped along with the following
LF without any processing. Then the bulk data can be read using a single
read operation that does not inspect the payload in any way. Finally
the remaining the CR and LF character are discarded without any processing.

While comparable in performance to a binary protocol the Redis protocol is
significantly simpler to implement in most very high level languages,
reducing the number of bugs in client software.

EVAL script numkeys key [key ...] arg [arg ...]

Introduction to EVAL

EVAL and EVALSHA are used to evaluate scripts using the Lua interpreter built into Redis starting from version 2.6.0.

The first argument of EVAL is a Lua 5.1 script. The script does not need to define a Lua function (and should not). It is just a Lua program that will run in the context of the Redis server.

The second argument of EVAL is the number of arguments that follows the script (starting from the third argument) that represent Redis key names. The arguments can be accessed by Lua using the KEYS global variable in the form of a one-based array (so KEYS[1], KEYS[2], …).

All the additional arguments should not represent key names and can be accessed by Lua using the ARGV global variable, very similarly to what happens with keys (so ARGV[1], ARGV[2], …).

The following example should clarify what stated above:

> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"

Note: as you can see Lua arrays are returned as Redis multi bulk replies, that is a Redis return type that your client library will likely convert into an Array type in your programming language.

It is possible to call Redis commands from a Lua script using two different Lua functions:

  • redis.call()
  • redis.pcall()

redis.call() is similar to redis.pcall(), the only difference is that if a Redis command call will result in an error, redis.call() will raise a Lua error that in turn will force EVAL to return an error to the command caller, while redis.pcall will trap the error and return a Lua table representing the error.

The arguments of the redis.call() and redis.pcall() functions are all the arguments of a well formed Redis command:

> eval "return redis.call('set','foo','bar')" 0
OK

The above script sets the key foo to the string bar. However it violates the EVAL command semantics as all the keys that the script uses should be passed using the KEYS array:

> eval "return redis.call('set',KEYS[1],'bar')" 1 foo
OK

All Redis commands must be analyzed before execution to determine which keys the command will operate on. In order for this to be true for EVAL, keys must be passed explicitly. This is useful in many ways, but especially to make sure Redis Cluster can forward your request to the appropriate cluster node.

Note this rule is not enforced in order to provide the user with opportunities to abuse the Redis single instance configuration, at the cost of writing scripts not compatible with Redis Cluster.

Lua scripts can return a value that is converted from the Lua type to the Redis protocol using a set of conversion rules.

Conversion between Lua and Redis data types

Redis return values are converted into Lua data types when Lua calls a Redis command using call() or pcall(). Similarly, Lua data types are converted into the Redis protocol when calling a Redis command and when a Lua script returns a value, so that scripts can control what EVAL will return to the client.

This conversion between data types is designed in a way that if a Redis type is converted into a Lua type, and then the result is converted back into a Redis type, the result is the same as the initial value.

In other words there is a one-to-one conversion between Lua and Redis types. The following table shows you all the conversions rules:

Redis to Lua conversion table.

  • Redis integer reply -> Lua number
  • Redis bulk reply -> Lua string
  • Redis multi bulk reply -> Lua table (may have other Redis data types nested)
  • Redis status reply -> Lua table with a single ok field containing the status
  • Redis error reply -> Lua table with a single err field containing the error
  • Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type

Lua to Redis conversion table.

  • Lua number -> Redis integer reply (the number is converted into an integer)
  • Lua string -> Redis bulk reply
  • Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside the Lua array if any)
  • Lua table with a single ok field -> Redis status reply
  • Lua table with a single err field -> Redis error reply
  • Lua boolean false -> Redis Nil bulk reply.

There is an additional Lua-to-Redis conversion rule that has no corresponding Redis to Lua conversion rule:

  • Lua boolean true -> Redis integer reply with value of 1.

Lastly, there are three important rules to note:

  • Lua has a single numerical type, Lua numbers. There is no distinction between integers and floats. So we always convert Lua numbers into integer replies, removing the decimal part of the number if any. If you want to return a float from Lua you should return it as a string, exactly like Redis itself does (see for instance the ZSCORE command).
  • There is no simple way to have nils inside Lua arrays, this is a result of Lua table semantics, so when Redis converts a Lua array into Redis protocol the conversion is stopped if a nil is encountered.
  • When a Lua table contains keys (and their values), the converted Redis reply will not include them.

RESP3 mode conversion rules: note that the Lua engine can work in RESP3 mode using the new Redis 6 protocol. In this case there are additional conversion rules, and certain conversions are also modified compared to the RESP2 mode. Please refer to the RESP3 section of this document for more information.

Here are a few conversion examples:

> eval "return 10" 0
(integer) 10

> eval "return {1,2,{3,'Hello World!'}}" 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 3
   2) "Hello World!"

> eval "return redis.call('get','foo')" 0
"bar"

The last example shows how it is possible to receive the exact return value of redis.call() or redis.pcall() from Lua that would be returned if the command was called directly.

In the following example we can see how floats and arrays containing nils and keys are handled:

> eval "return {1,2,3.3333,somekey='somevalue','foo',nil,'bar'}" 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) "foo"

As you can see 3.333 is converted into 3, somekey is excluded, and the bar string is never returned as there is a nil before.

Helper functions to return Redis types

There are two helper functions to return Redis types from Lua.

  • redis.error_reply(error_string) returns an error reply. This function simply returns a single field table with the err field set to the specified string for you.
  • redis.status_reply(status_string) returns a status reply. This function simply returns a single field table with the ok field set to the specified string for you.

There is no difference between using the helper functions or directly returning the table with the specified format, so the following two forms are equivalent:

return {err="My Error"}
return redis.error_reply("My Error")

Atomicity of scripts

Redis uses the same Lua interpreter to run all the commands. Also Redis guarantees that a script is executed in an atomic way: no other script or Redis command will be executed while a script is being executed. This semantic is similar to the one of MULTI / EXEC. From the point of view of all the other clients the effects of a script are either still not visible or already completed.

However this also means that executing slow scripts is not a good idea. It is not hard to create fast scripts, as the script overhead is very low, but if you are going to use slow scripts you should be aware that while the script is running no other client can execute commands.

Error handling

As already stated, calls to redis.call() resulting in a Redis command error will stop the execution of the script and return an error, in a way that makes it obvious that the error was generated by a script:

> del foo
(integer) 1
> lpush foo a
(integer) 1
> eval "return redis.call('get','foo')" 0
(error) ERR Error running script (call to f_6b1bf486c81ceb7edf3c093f4c48582e38c0e791): ERR Operation against a key holding the wrong kind of value

Using redis.pcall() no error is raised, but an error object is returned in the format specified above (as a Lua table with an err field). The script can pass the exact error to the user by returning the error object returned by redis.pcall().

Bandwidth and EVALSHA

The EVAL command forces you to send the script body again and again. Redis does not need to recompile the script every time as it uses an internal caching mechanism, however paying the cost of the additional bandwidth may not be optimal in many contexts.

On the other hand, defining commands using a special command or via redis.conf would be a problem for a few reasons:

  • Different instances may have different implementations of a command.

  • Deployment is hard if we have to make sure all instances contain a given command, especially in a distributed environment.

  • Reading application code, the complete semantics might not be clear since the application calls commands defined server side.

In order to avoid these problems while avoiding the bandwidth penalty, Redis implements the EVALSHA command.

EVALSHA works exactly like EVAL, but instead of having a script as the first argument it has the SHA1 digest of a script. The behavior is the following:

  • If the server still remembers a script with a matching SHA1 digest, the script is executed.

  • If the server does not remember a script with this SHA1 digest, a special error is returned telling the client to use EVAL instead.

Example:

> set foo bar
OK
> eval "return redis.call('get','foo')" 0
"bar"
> evalsha 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 0
"bar"
> evalsha ffffffffffffffffffffffffffffffffffffffff 0
(error) `NOSCRIPT` No matching script. Please use [EVAL](/commands/eval).

The client library implementation can always optimistically send EVALSHA under the hood even when the client actually calls EVAL, in the hope the script was already seen by the server. If the NOSCRIPT error is returned EVAL will be used instead.

Passing keys and arguments as additional EVAL arguments is also very useful in this context as the script string remains constant and can be efficiently cached by Redis.

Script cache semantics

Executed scripts are guaranteed to be in the script cache of a given execution of a Redis instance forever. This means that if an EVAL is performed against a Redis instance all the subsequent EVALSHA calls will succeed.

The reason why scripts can be cached for long time is that it is unlikely for a well written application to have enough different scripts to cause memory problems. Every script is conceptually like the implementation of a new command, and even a large application will likely have just a few hundred of them. Even if the application is modified many times and scripts will change, the memory used is negligible.

The only way to flush the script cache is by explicitly calling the SCRIPT FLUSH command, which will completely flush the scripts cache removing all the scripts executed so far.

This is usually needed only when the instance is going to be instantiated for another customer or application in a cloud environment.

Also, as already mentioned, restarting a Redis instance flushes the script cache, which is not persistent. However from the point of view of the client there are only two ways to make sure a Redis instance was not restarted between two different commands.

  • The connection we have with the server is persistent and was never closed so far.
  • The client explicitly checks the runid field in the INFO command in order to make sure the server was not restarted and is still the same process.

Practically speaking, for the client it is much better to simply assume that in the context of a given connection, cached scripts are guaranteed to be there unless an administrator explicitly called the SCRIPT FLUSH command.

The fact that the user can count on Redis not removing scripts is semantically useful in the context of pipelining.

For instance an application with a persistent connection to Redis can be sure that if a script was sent once it is still in memory, so EVALSHA can be used against those scripts in a pipeline without the chance of an error being generated due to an unknown script (we’ll see this problem in detail later).

A common pattern is to call SCRIPT LOAD to load all the scripts that will appear in a pipeline, then use EVALSHA directly inside the pipeline without any need to check for errors resulting from the script hash not being recognized.

The SCRIPT command

Redis offers a SCRIPT command that can be used in order to control the scripting subsystem. SCRIPT currently accepts three different commands:

  • SCRIPT FLUSH

    This command is the only way to force Redis to flush the scripts cache. It is most useful in a cloud environment where the same instance can be reassigned to a different user. It is also useful for testing client libraries’ implementations of the scripting feature.

  • SCRIPT EXISTS sha1 sha2 ... shaN

    Given a list of SHA1 digests as arguments this command returns an array of 1 or 0, where 1 means the specific SHA1 is recognized as a script already present in the scripting cache, while 0 means that a script with this SHA1 was never seen before (or at least never seen after the latest SCRIPT FLUSH command).

  • SCRIPT LOAD script

    This command registers the specified script in the Redis script cache. The command is useful in all the contexts where we want to make sure that EVALSHA will not fail (for instance during a pipeline or MULTI/EXEC operation), without the need to actually execute the script.

  • SCRIPT KILL

    This command is the only way to interrupt a long-running script that reaches the configured maximum execution time for scripts. The SCRIPT KILL command can only be used with scripts that did not modify the dataset during their execution (since stopping a read-only script does not violate the scripting engine’s guaranteed atomicity). See the next sections for more information about long running scripts.

Scripts as pure functions

Note: starting with Redis 5, scripts are always replicated as effects and not sending the script verbatim. So the following section is mostly applicable to Redis version 4 or older.

A very important part of scripting is writing scripts that are pure functions. Scripts executed in a Redis instance are, by default, propagated to replicas and to the AOF file by sending the script itself — not the resulting commands.

The reason is that sending a script to another Redis instance is often much faster than sending the multiple commands the script generates, so if the client is sending many scripts to the master, converting the scripts into individual commands for the replica / AOF would result in too much bandwidth for the replication link or the Append Only File (and also too much CPU since dispatching a command received via network is a lot more work for Redis compared to dispatching a command invoked by Lua scripts).

Normally replicating scripts instead of the effects of the scripts makes sense, however not in all the cases. So starting with Redis 3.2, the scripting engine is able to, alternatively, replicate the sequence of write commands resulting from the script execution, instead of replication the script itself. See the next section for more information. In this section we’ll assume that scripts are replicated by sending the whole script. Let’s call this replication mode whole scripts replication.

The main drawback with the whole scripts replication approach is that scripts are required to have the following property:

  • The script must always evaluates the same Redis write commands with the same arguments given the same input data set. Operations performed by the script cannot depend on any hidden (non-explicit) information or state that may change as script execution proceeds or between different executions of the script, nor can it depend on any external input from I/O devices.

Things like using the system time, calling Redis random commands like RANDOMKEY, or using Lua random number generator, could result into scripts that will not always evaluate in the same way.

In order to enforce this behavior in scripts Redis does the following:

  • Lua does not export commands to access the system time or other external state.
  • 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).
  • In Redis version 4, commands that may return elements in random order, like SMEMBERS (because Redis Sets are unordered) have a different behavior when called from Lua, and undergo a silent lexicographical sorting filter before returning data to Lua scripts. So redis.call("smembers",KEYS[1]) will always return the Set elements in the same order, while the same command invoked from normal clients may return different results even if the key contains exactly the same elements. However starting with Redis 5 there is no longer such ordering step, because Redis 5 replicates scripts in a way that no longer needs non-deterministic commands to be converted into deterministic ones. In general, even when developing for Redis 4, never assume that certain commands in Lua will be ordered, but instead rely on the documentation of the original command you call to see the properties it provides.
  • Lua pseudo random number generation functions math.random and math.randomseed are modified in order to always have the same seed every time a new script is executed. This means that calling math.random will always generate the same sequence of numbers every time a script is executed if math.randomseed is not used.

However the user is still able to write commands with random behavior using the following simple trick. Imagine I want to write a Redis script that will populate a list with N random integers.

I can start with this small Ruby program:

require 'rubygems'
require 'redis'

r = Redis.new

RandomPushScript = <<EOF
    local i = tonumber(ARGV[1])
    local res
    while (i > 0) do
        res = redis.call('lpush',KEYS[1],math.random())
        i = i-1
    end
    return res
EOF

r.del(:mylist)
puts r.eval(RandomPushScript,[:mylist],[10,rand(2**32)])

Every time this script executed the resulting list will have exactly the following elements:

> lrange mylist 0 -1
 1) "0.74509509873814"
 2) "0.87390407681181"
 3) "0.36876626981831"
 4) "0.6921941534114"
 5) "0.7857992587545"
 6) "0.57730350670279"
 7) "0.87046522734243"
 8) "0.09637165539729"
 9) "0.74990198051087"
10) "0.17082803611217"

In order to make it a pure function, but still be sure that every invocation of the script will result in different random elements, we can simply add an additional argument to the script that will be used in order to seed the Lua pseudo-random number generator. The new script is as follows:

RandomPushScript = <<EOF
    local i = tonumber(ARGV[1])
    local res
    math.randomseed(tonumber(ARGV[2]))
    while (i > 0) do
        res = redis.call('lpush',KEYS[1],math.random())
        i = i-1
    end
    return res
EOF

r.del(:mylist)
puts r.eval(RandomPushScript,1,:mylist,10,rand(2**32))

What we are doing here is sending the seed of the PRNG as one of the arguments. This way the script output will be the same given the same arguments, but we are changing one of the arguments in every invocation, generating the random seed client-side. The seed will be propagated as one of the arguments both in the replication link and in the Append Only File, guaranteeing that the same changes will be generated when the AOF is reloaded or when the replica processes the script.

Note: an important part of this behavior is that the PRNG that Redis implements as math.random and math.randomseed is guaranteed to have the same output regardless of the architecture of the system running Redis. 32-bit, 64-bit, big-endian and little-endian systems will all produce the same output.

Replicating commands instead of scripts

Note: starting with Redis 5, the replication method described in this section (scripts effects replication) is the default and does not need to be explicitly enabled.

Starting with Redis 3.2, it is possible to select an alternative replication method. Instead of replication whole scripts, we can just replicate single write commands generated by the script. We call this script effects replication.

In this replication mode, while Lua scripts are executed, Redis collects all the commands executed by the Lua scripting engine that actually modify the dataset. When the script execution finishes, the sequence of commands that the script generated are wrapped into a MULTI / EXEC transaction and are sent to replicas and AOF.

This is useful in several ways depending on the use case:

  • When the script is slow to compute, but the effects can be summarized by a few write commands, it is a shame to re-compute the script on the replicas or when reloading the AOF. In this case to replicate just the effect of the script is much better.
  • When script effects replication is enabled, the controls about non deterministic functions are disabled. You can, for example, use the TIME or SRANDMEMBER commands inside your scripts freely at any place.
  • The Lua PRNG in this mode is seeded randomly at every call.

In order to enable script effects replication, you need to issue the following Lua command before any write operated by the script:

redis.replicate_commands()

The function returns true if the script effects replication was enabled, otherwise if the function was called after the script already called some write command, it returns false, and normal whole script replication is used.

Selective replication of commands

When script effects replication is selected (see the previous section), it is possible to have more control in the way commands are replicated to replicas and AOF. This is a very advanced feature since a misuse can do damage by breaking the contract that the master, replicas, and AOF, all must contain the same logical content.

However this is a useful feature since, sometimes, we need to execute certain commands only in the master in order to create, for example, intermediate values.

Think at a Lua script where we perform an intersection between two sets. Pick five random elements, and create a new set with this five random elements. Finally we delete the temporary key representing the intersection between the two original sets. What we want to replicate is only the creation of the new set with the five elements. It’s not useful to also replicate the commands creating the temporary key.

For this reason, Redis 3.2 introduces a new command that only works when script effects replication is enabled, and is able to control the scripting replication engine. The command is called redis.set_repl() and fails raising an error if called when script effects replication is disabled.

The command can be called with four different arguments:

redis.set_repl(redis.REPL_ALL) -- Replicate to AOF and replicas.
redis.set_repl(redis.REPL_AOF) -- Replicate only to AOF.
redis.set_repl(redis.REPL_REPLICA) -- Replicate only to replicas (Redis >= 5)
redis.set_repl(redis.REPL_SLAVE) -- Used for backward compatibility, the same as REPL_REPLICA.
redis.set_repl(redis.REPL_NONE) -- Don't replicate at all.

By default the scripting engine is always set to REPL_ALL. By calling this function the user can switch on/off AOF and or replicas propagation, and turn them back later at her/his wish.

A simple example follows:

redis.replicate_commands() -- Enable effects replication.
redis.call('set','A','1')
redis.set_repl(redis.REPL_NONE)
redis.call('set','B','2')
redis.set_repl(redis.REPL_ALL)
redis.call('set','C','3')

After running the above script, the result is that only keys A and C will be created on replicas and AOF.

Global variables protection

Redis scripts are not allowed to create global variables, in order to avoid leaking data into the Lua state. If a script needs to maintain state between calls (a pretty uncommon need) it should use Redis keys instead.

When global variable access is attempted the script is terminated and EVAL returns with an error:

redis 127.0.0.1:6379> eval 'a=10' 0
(error) ERR Error running script (call to f_933044db579a2f8fd45d8065f04a8d0249383e57): user_script:1: Script attempted to create global variable 'a'

Accessing a non existing global variable generates a similar error.

Using Lua debugging functionality or other approaches like altering the meta table used to implement global protections in order to circumvent globals protection is not hard. However it is difficult to do it accidentally. If the user messes with the Lua global state, the consistency of AOF and replication is not guaranteed: don’t do it.

Note for Lua newbies: in order to avoid using global variables in your scripts simply declare every variable you are going to use using the local keyword.

Using SELECT inside scripts

It is possible to call SELECT inside Lua scripts like with normal clients, However one subtle aspect of the behavior changes between Redis 2.8.11 and Redis 2.8.12. Before the 2.8.12 release the database selected by the Lua script was transferred to the calling script as current database. Starting from Redis 2.8.12 the database selected by the Lua script only affects the execution of the script itself, but does not modify the database selected by the client calling the script.

The semantic change between patch level releases was needed since the old behavior was inherently incompatible with the Redis replication layer and was the cause of bugs.

Using Lua scripting in RESP3 mode

Starting with Redis version 6, the server supports two different protocols. One is called RESP2, and is the old protocol: all the new connections to the server start in this mode. However clients are able to negotiate the new protocol using the HELLO command: this way the connection is put in RESP3 mode. In this mode certain commands, like for instance HGETALL, reply with a new data type (the Map data type in this specific case). The RESP3 protocol is semantically more powerful, however most scripts are OK with using just RESP2.

The Lua engine always assumes to run in RESP2 mode when talking with Redis, so whatever the connection that is invoking the EVAL or EVALSHA command is in RESP2 or RESP3 mode, Lua scripts will, by default, still see the same kind of replies they used to see in the past from Redis, when calling commands using the redis.call() built-in function.

However Lua scripts running in Redis 6 or greater, are able to switch to RESP3 mode, and get the replies using the new available types. Similarly Lua scripts are able to reply to clients using the new types. Please make sure to understand the capabilities for RESP3 before continuing reading this section.

In order to switch to RESP3 a script should call this function:

redis.setresp(3)

Note that a script can switch back and forth from RESP3 and RESP2 by calling the function with the argument ‘3’ or ‘2’.

At this point the new conversions are available, specifically:

Redis to Lua conversion table specific to RESP3:

  • Redis map reply -> Lua table with a single map field containing a Lua table representing the fields and values of the map.
  • Redis set reply -> Lua table with a single set field containing a Lua table representing the elements of the set as fields, having as value just true.
  • Redis new RESP3 single null value -> Lua nil.
  • Redis true reply -> Lua true boolean value.
  • Redis false reply -> Lua false boolean value.
  • Redis double reply -> Lua table with a single score field containing a Lua number representing the double value.
  • All the RESP2 old conversions still apply.

Lua to Redis conversion table specific for RESP3.

  • Lua boolean -> Redis boolean true or false. Note that this is a change compared to the RESP2 mode, where returning true from Lua returned the number 1 to the Redis client, and returning false used to return NULL.
  • Lua table with a single map field set to a field-value Lua table -> Redis map reply.
  • Lua table with a single set field set to a field-value Lua table -> Redis set reply, the values are discarded and can be anything.
  • Lua table with a single double field set to a field-value Lua table -> Redis double reply.
  • Lua null -> Redis RESP3 new null reply (protocol "_rn").
  • All the RESP2 old conversions still apply unless specified above.

There is one key thing to understand: in case Lua replies with RESP3 types, but the connection calling Lua is in RESP2 mode, Redis will automatically convert the RESP3 protocol to RESP2 compatible protocol, as it happens for normal commands. For instance returning a map type to a connection in RESP2 mode will have the effect of returning a flat array of fields and values.

Available libraries

The Redis Lua interpreter loads the following Lua libraries:

  • base lib.
  • table lib.
  • string lib.
  • math lib.
  • struct lib.
  • cjson lib.
  • cmsgpack lib.
  • bitop lib.
  • redis.sha1hex function.
  • redis.breakpoint and redis.debug function in the context of the Redis Lua debugger.

Every Redis instance is guaranteed to have all the above libraries so you can be sure that the environment for your Redis scripts is always the same.

struct, CJSON and cmsgpack are external libraries, all the other libraries are standard Lua libraries.

struct

struct is a library for packing/unpacking structures within Lua.

Valid formats:
> - big endian
< - little endian
![num] - alignment
x - pading
b/B - signed/unsigned byte
h/H - signed/unsigned short
l/L - signed/unsigned long
T   - size_t
i/In - signed/unsigned integer with size `n' (default is size of int)
cn - sequence of `n' chars (from/to a string); when packing, n==0 means
     the whole string; when unpacking, n==0 means use the previous
     read number as the string length
s - zero-terminated string
f - float
d - double
' ' - ignored

Example:

127.0.0.1:6379> eval 'return struct.pack("HH", 1, 2)' 0
"x01x00x02x00"
127.0.0.1:6379> eval 'return {struct.unpack("HH", ARGV[1])}' 0 "x01x00x02x00"
1) (integer) 1
2) (integer) 2
3) (integer) 5
127.0.0.1:6379> eval 'return struct.size("HH")' 0
(integer) 4

CJSON

The CJSON library provides extremely fast JSON manipulation within Lua.

Example:

redis 127.0.0.1:6379> eval 'return cjson.encode({["foo"]= "bar"})' 0
"{"foo":"bar"}"
redis 127.0.0.1:6379> eval 'return cjson.decode(ARGV[1])["foo"]' 0 "{"foo":"bar"}"
"bar"

cmsgpack

The cmsgpack library provides simple and fast MessagePack manipulation within Lua.

Example:

127.0.0.1:6379> eval 'return cmsgpack.pack({"foo", "bar", "baz"})' 0
"x93xa3fooxa3barxa3baz"
127.0.0.1:6379> eval 'return cmsgpack.unpack(ARGV[1])' 0 "x93xa3fooxa3barxa3baz"
1) "foo"
2) "bar"
3) "baz"

bitop

The Lua Bit Operations Module adds bitwise operations on numbers. It is available for scripting in Redis since version 2.8.18.

Example:

127.0.0.1:6379> eval 'return bit.tobit(1)' 0
(integer) 1
127.0.0.1:6379> eval 'return bit.bor(1,2,4,8,16,32,64,128)' 0
(integer) 255
127.0.0.1:6379> eval 'return bit.tohex(422342)' 0
"000671c6"

It supports several other functions: bit.tobit, bit.tohex, bit.bnot, bit.band, bit.bor, bit.bxor, bit.lshift, bit.rshift, bit.arshift, bit.rol, bit.ror, bit.bswap. All available functions are documented in the Lua BitOp documentation

redis.sha1hex

Perform the SHA1 of the input string.

Example:

127.0.0.1:6379> eval 'return redis.sha1hex(ARGV[1])' 0 "foo"
"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"

Emitting Redis logs from scripts

It is possible to write to the Redis log file from Lua scripts using the redis.log function.

redis.log(loglevel,message)

loglevel is one of:

  • redis.LOG_DEBUG
  • redis.LOG_VERBOSE
  • redis.LOG_NOTICE
  • redis.LOG_WARNING

They correspond directly to the normal Redis log levels. Only logs emitted by scripting using a log level that is equal or greater than the currently configured Redis instance log level will be emitted.

The message argument is simply a string. Example:

redis.log(redis.LOG_WARNING,"Something is wrong with this script.")

Will generate the following:

[32343] 22 Mar 15:21:39 # Something is wrong with this script.

Sandbox and maximum execution time

Scripts should never try to access the external system, like the file system or any other system call. A script should only operate on Redis data and passed arguments.

Scripts are also subject to a maximum execution time (five seconds by default). This default timeout is huge since a script should usually run in under a millisecond. The limit is mostly to handle accidental infinite loops created during development.

It is possible to modify the maximum time a script can be executed with millisecond precision, either via redis.conf or using the CONFIG GET / CONFIG SET command. The configuration parameter affecting max execution time is called lua-time-limit.

When a script reaches the timeout it is not automatically terminated by Redis since this violates the contract Redis has with the scripting engine to ensure that scripts are atomic. Interrupting a script means potentially leaving the dataset with half-written data. For this reasons when a script executes for more than the specified time the following happens:

  • Redis logs that a script is running too long.
  • It starts accepting commands again from other clients, but will reply with a BUSY error to all the clients sending normal commands. The only allowed commands in this status are SCRIPT KILL and SHUTDOWN
    NOSAVE
    .
  • It is possible to terminate a script that executes only read-only commands using the SCRIPT KILL command. This does not violate the scripting semantic as no data was yet written to the dataset by the script.
  • If the script already called write commands the only allowed command becomes SHUTDOWN NOSAVE that stops the server without saving the current data set on disk (basically the server is aborted).

EVALSHA in the context of pipelining

Care should be taken when executing EVALSHA in the context of a pipelined request, since even in a pipeline the order of execution of commands must be guaranteed. If EVALSHA will return a NOSCRIPT error the command can not be reissued later otherwise the order of execution is violated.

The client library implementation should take one of the following approaches:

  • Always use plain EVAL when in the context of a pipeline.

  • Accumulate all the commands to send into the pipeline, then check for EVAL commands and use the SCRIPT EXISTS command to check if all the scripts are already defined. If not, add SCRIPT LOAD commands on top of the pipeline as required, and use EVALSHA for all the EVAL calls.

Debugging Lua scripts

Starting with Redis 3.2, Redis has support for native Lua debugging. The Redis Lua debugger is a remote debugger consisting of a server, which is Redis itself, and a client, which is by default redis-cli.

The Lua debugger is described in the Lua scripts debugging section of the Redis documentation.

© 2009–2020 Salvatore Sanfilippo
Licensed under the Creative Commons Attribution-ShareAlike License 4.0.
https://redis.io/commands/eval

Содержание

  1. Node js redis on error
  2. Node Redis
  3. A high performance Node.js Redis client.
  4. Installation
  5. Usage
  6. Example
  7. Promises
  8. Commands
  9. Connection and other Events
  10. «ready»
  11. «connect»
  12. «reconnecting»
  13. «error»
  14. «warning»
  15. redis.createClient()
  16. options object properties
  17. client.auth(password[, callback])
  18. client.quit(callback)
  19. client.end(flush)
  20. Error Handling
  21. Example
  22. client.unref()
  23. Hash Commands
  24. client.hgetall(hash, callback)
  25. client.hmset(hash, key1, val1, . keyN, valN, [callback])
  26. PubSub
  27. Example
  28. Subscriber Events
  29. client.multi([commands])
  30. Multi.exec([callback])
  31. Multi.exec_atomic([callback])
  32. Optimistic Locks
  33. WATCH limitations
  34. client.batch([commands])
  35. Monitor mode
  36. Example:
  37. Extras
  38. client.server_info
  39. redis.print()
  40. Multi-word commands
  41. client.duplicate([options][, callback])
  42. client.sendCommand(command_name[, [args][, callback]])
  43. redis.addCommand(command_name)
  44. client.connected
  45. client.command_queue_length
  46. client.offline_queue_length
  47. Commands with Optional and Keyword arguments
  48. Example
  49. Performance
  50. Debugging
  51. Contributing
  52. License

Node js redis on error

Node Redis

A high performance Node.js Redis client.

Installation

Usage

Example

Note that the API is entirely asynchronous. To get data back from the server, you’ll need to use a callback.

Promises

Node Redis currently doesn’t natively support promises (this is coming in v4), however you can wrap the methods you want to use with promises using the built-in Node.js util.promisify method on Node.js >= v8;

Commands

This library is a 1 to 1 mapping of the Redis commands.

Each Redis command is exposed as a function on the client object. All functions take either an args Array plus optional callback Function or a variable number of individual arguments followed by an optional callback. Examples:

Care should be taken with user input if arrays are possible (via body-parser, query string or other method), as single arguments could be unintentionally interpreted as multiple args.

Note that in either form the callback is optional:

If the key is missing, reply will be null. Only if the Redis Command Reference states something else it will not be null.

Minimal parsing is done on the replies. Commands that return a integer return JavaScript Numbers, arrays return JavaScript Array. HGETALL returns an Object keyed by the hash keys. All strings will either be returned as string or as buffer depending on your setting. Please be aware that sending null, undefined and Boolean values will result in the value coerced to a string!

Connection and other Events

client will emit some events about the state of the connection to the Redis server.

«ready»

client will emit ready once a connection is established. Commands issued before the ready event are queued, then replayed just before this event is emitted.

«connect»

client will emit connect as soon as the stream is connected to the server.

«reconnecting»

client will emit reconnecting when trying to reconnect to the Redis server after losing the connection. Listeners are passed an object containing delay (in ms from the previous try) and attempt (the attempt #) attributes.

«error»

client will emit error when encountering an error connecting to the Redis server or when any other in Node Redis occurs. If you use a command without callback and encounter a ReplyError it is going to be emitted to the error listener.

So please attach the error listener to Node Redis.

client will emit end when an established Redis server connection has closed.

«warning»

client will emit warning when password was set but none is needed and if a deprecated option / function / similar is used.

redis.createClient()

If you have redis-server running on the same machine as node, then the defaults for port and host are probably fine and you don’t need to supply any arguments. createClient() returns a RedisClient object. Otherwise, createClient() accepts these arguments:

  • redis.createClient([options])
  • redis.createClient(unix_socket[, options])
  • redis.createClient(redis_url[, options])
  • redis.createClient(port[, host][, options])

Tip: If the Redis server runs on the same machine as the client consider using unix sockets if possible to increase throughput.

Note: Using ‘rediss://. for the protocol in a redis_url will enable a TLS socket connection. However, additional TLS options will need to be passed in options , if required.

options object properties

Property Default Description
host 127.0.0.1 IP address of the Redis server
port 6379 Port of the Redis server
path null The UNIX socket string of the Redis server
url null The URL of the Redis server. Format: [redis[s]:]//[[user][:password@]][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]] (More info avaliable at IANA).
string_numbers null Set to true , Node Redis will return Redis number values as Strings instead of javascript Numbers. Useful if you need to handle big numbers (above Number.MAX_SAFE_INTEGER === 2^53 ). Hiredis is incapable of this behavior, so setting this option to true will result in the built-in javascript parser being used no matter the value of the parser option.
return_buffers false If set to true , then all replies will be sent to callbacks as Buffers instead of Strings.
detect_buffers false If set to true , then replies will be sent to callbacks as Buffers. This option lets you switch between Buffers and Strings on a per-command basis, whereas return_buffers applies to every command on a client. Note: This doesn’t work properly with the pubsub mode. A subscriber has to either always return Strings or Buffers.
socket_keepalive true If set to true , the keep-alive functionality is enabled on the underlying socket.
socket_initial_delay Initial Delay in milliseconds, and this will also behave the interval keep alive message sending to Redis.
no_ready_check false When a connection is established to the Redis server, the server might still be loading the database from disk. While loading, the server will not respond to any commands. To work around this, Node Redis has a «ready check» which sends the INFO command to the server. The response from the INFO command indicates whether the server is ready for more commands. When ready, node_redis emits a ready event. Setting no_ready_check to true will inhibit this check.
enable_offline_queue true By default, if there is no active connection to the Redis server, commands are added to a queue and are executed once the connection has been established. Setting enable_offline_queue to false will disable this feature and the callback will be executed immediately with an error, or an error will be emitted if no callback is specified.
retry_unfulfilled_commands false If set to true , all commands that were unfulfilled while the connection is lost will be retried after the connection has been reestablished. Use this with caution if you use state altering commands (e.g. incr ). This is especially useful if you use blocking commands.
password null If set, client will run Redis auth command on connect. Alias auth_pass Note Node Redis auth_pass
user null The ACL user (only valid when password is set)
db null If set, client will run Redis select command on connect.
family IPv4 You can force using IPv6 if you set the family to ‘IPv6’. See Node.js net or dns modules on how to use the family type.
disable_resubscribing false If set to true , a client won’t resubscribe after disconnecting.
rename_commands null Passing an object with renamed commands to use instead of the original functions. For example, if you renamed the command KEYS to «DO-NOT-USE» then the rename_commands object would be: < KEYS : «DO-NOT-USE» >. See the Redis security topics for more info.
tls null An object containing options to pass to tls.connect to set up a TLS connection to Redis (if, for example, it is set up to be accessible via a tunnel).
prefix null A string used to prefix all used keys (e.g. namespace:test ). Please be aware that the keys command will not be prefixed. The keys command has a «pattern» as argument and no key and it would be impossible to determine the existing keys in Redis if this would be prefixed.
retry_strategy function A function that receives an options object as parameter including the retry attempt , the total_retry_time indicating how much time passed since the last time connected, the error why the connection was lost and the number of times_connected in total. If you return a number from this function, the retry will happen exactly after that time in milliseconds. If you return a non-number, no further retry will happen and all offline commands are flushed with errors. Return an error to return that specific error to all offline commands. Example below.
connect_timeout 3600000 In milliseconds. This should only be the timeout for connecting to redis, but for now it interferes with retry_strategy and stops it from reconnecting after this timeout.

detect_buffers example:

retry_strategy example:

client.auth(password[, callback])

When connecting to a Redis server that requires authentication, the AUTH command must be sent as the first command after connecting. This can be tricky to coordinate with reconnections, the ready check, etc. To make this easier, client.auth() stashes password and will send it after each connection, including reconnections. callback is invoked only once, after the response to the very first AUTH command sent. NOTE: Your call to client.auth() should not be inside the ready handler. If you are doing this wrong, client will emit an error that looks something like this Error: Ready check failed: ERR operation not permitted .

client.quit(callback)

This sends the quit command to the redis server and ends cleanly right after all running commands were properly handled. If this is called while reconnecting (and therefore no connection to the redis server exists) it is going to end the connection right away instead of resulting in further reconnections! All offline commands are going to be flushed with an error in that case.

client.end(flush)

Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed. If you want to exit cleanly, call client.quit() as mentioned above.

You should set flush to true, if you are not absolutely sure you do not care about any other commands. If you set flush to false all still running commands will silently fail.

This example closes the connection to the Redis server before the replies have been read. You probably don’t want to do this:

client.end() without the flush parameter set to true should NOT be used in production!

Error Handling

Currently the following Error subclasses exist:

  • RedisError : All errors returned by the client
  • ReplyError subclass of RedisError : All errors returned by Redis itself
  • AbortError subclass of RedisError : All commands that could not finish due to what ever reason
  • ParserError subclass of RedisError : Returned in case of a parser error (this should not happen)
  • AggregateError subclass of AbortError : Emitted in case multiple unresolved commands without callback got rejected in debug_mode instead of lots of AbortError s.

All error classes are exported by the module.

Example

Every ReplyError contains the command name in all-caps and the arguments ( args ).

If Node Redis emits a library error because of another error, the triggering error is added to the returned error as origin attribute.

Error codes

Node Redis returns a NR_CLOSED error code if the clients connection dropped. If a command unresolved command got rejected a UNCERTAIN_STATE code is returned. A CONNECTION_BROKEN error code is used in case Node Redis gives up to reconnect.

client.unref()

Call unref() on the underlying socket connection to the Redis server, allowing the program to exit once no more commands are pending.

This is an experimental feature, and only supports a subset of the Redis protocol. Any commands where client state is saved on the Redis server, e.g. *SUBSCRIBE or the blocking BL* commands will NOT work with .unref() .

Hash Commands

Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings. When dealing with hash values, there are a couple of useful exceptions to this.

client.hgetall(hash, callback)

The reply from an HGETALL command will be converted into a JavaScript Object. That way you can interact with the responses using JavaScript syntax.

Example:

client.hmset(hash, key1, val1, . keyN, valN, [callback])

Multiple values may also be set by supplying more arguments.

Example:

PubSub

Example

This example opens two client connections, subscribes to a channel on one of them, and publishes to that channel on the other.

When a client issues a SUBSCRIBE or PSUBSCRIBE , that connection is put into a «subscriber» mode. At that point, the only valid commands are those that modify the subscription set, and quit (also ping on some redis versions). When the subscription set is empty, the connection is put back into regular mode.

If you need to send regular commands to Redis while in subscriber mode, just open another connection with a new client (use client.duplicate() to quickly duplicate an existing client).

Subscriber Events

If a client has subscriptions active, it may emit these events:

«message» (channel, message):

Client will emit message for every message received that matches an active subscription. Listeners are passed the channel name as channel and the message as message .

«pmessage» (pattern, channel, message):

Client will emit pmessage for every message received that matches an active subscription pattern. Listeners are passed the original pattern used with PSUBSCRIBE as pattern , the sending channel name as channel , and the message as message .

«message_buffer» (channel, message):

This is the same as the message event with the exception, that it is always going to emit a buffer. If you listen to the message event at the same time as the message_buffer , it is always going to emit a string.

«pmessage_buffer» (pattern, channel, message):

This is the same as the pmessage event with the exception, that it is always going to emit a buffer. If you listen to the pmessage event at the same time as the pmessage_buffer , it is always going to emit a string.

«subscribe» (channel, count):

Client will emit subscribe in response to a SUBSCRIBE command. Listeners are passed the channel name as channel and the new count of subscriptions for this client as count .

«psubscribe» (pattern, count):

Client will emit psubscribe in response to a PSUBSCRIBE command. Listeners are passed the original pattern as pattern , and the new count of subscriptions for this client as count .

«unsubscribe» (channel, count):

Client will emit unsubscribe in response to a UNSUBSCRIBE command. Listeners are passed the channel name as channel and the new count of subscriptions for this client as count . When count is 0, this client has left subscriber mode and no more subscriber events will be emitted.

«punsubscribe» (pattern, count):

Client will emit punsubscribe in response to a PUNSUBSCRIBE command. Listeners are passed the channel name as channel and the new count of subscriptions for this client as count . When count is 0, this client has left subscriber mode and no more subscriber events will be emitted.

client.multi([commands])

MULTI commands are queued up until an EXEC is issued, and then all commands are run atomically by Redis. The interface returns an individual Multi object by calling client.multi() . If any command fails to queue, all commands are rolled back and none is going to be executed (For further information see the Redis transactions documentation).

Multi.exec([callback])

client.multi() is a constructor that returns a Multi object. Multi objects share all of the same command methods as client objects do. Commands are queued up inside the Multi object until Multi.exec() is invoked.

If your code contains an syntax error an EXECABORT error is going to be thrown and all commands are going to be aborted. That error contains a .errors property that contains the concrete errors. If all commands were queued successfully and an error is thrown by redis while processing the commands that error is going to be returned in the result array! No other command is going to be aborted though than the ones failing.

You can either chain together MULTI commands as in the above example, or you can queue individual commands while still sending regular client command as in this example:

In addition to adding commands to the MULTI queue individually, you can also pass an array of commands and arguments to the constructor:

Multi.exec_atomic([callback])

Identical to Multi.exec but with the difference that executing a single command will not use transactions.

Optimistic Locks

Using multi you can make sure your modifications run as a transaction, but you can’t be sure you got there first. What if another client modified a key while you were working with it’s data?

To solve this, Redis supports the WATCH command, which is meant to be used with MULTI:

The above snippet shows the correct usage of watch with multi . Every time a watched key is changed before the execution of a multi command, the execution will return null . On a normal situation, the execution will return an array of values with the results of the operations.

As stated in the snippet, failing the execution of a multi command being watched is not considered an error. The execution may return an error if, for example, the client cannot connect to Redis.

An example where we can see the execution of a multi command fail is as follows:

WATCH limitations

Redis WATCH works only on whole key values. For example, with WATCH you can watch a hash for modifications, but you cannot watch a specific field of a hash.

The following example would watch the keys foo and hello , not the field hello of hash foo :

This limitation also applies to sets (you can not watch individual set members) and any other collections.

client.batch([commands])

Identical to .multi() without transactions. This is recommended if you want to execute many commands at once but don’t need to rely on transactions.

BATCH commands are queued up until an EXEC is issued, and then all commands are run atomically by Redis. The interface returns an individual Batch object by calling client.batch() . The only difference between .batch and .multi is that no transaction is going to be used. Be aware that the errors are — just like in multi statements — in the result. Otherwise both, errors and results could be returned at the same time.

If you fire many commands at once this is going to boost the execution speed significantly compared to firing the same commands in a loop without waiting for the result! See the benchmarks for further comparison. Please remember that all commands are kept in memory until they are fired.

Monitor mode

Redis supports the MONITOR command, which lets you see all commands received by the Redis server across all client connections, including from other client libraries and other computers.

A monitor event is going to be emitted for every command fired from any client connected to the server including the monitoring client itself. The callback for the monitor event takes a timestamp from the Redis server, an array of command arguments and the raw monitoring string.

Example:

Some other things you might find useful.

client.server_info

After the ready probe completes, the results from the INFO command are saved in the client.server_info object.

The versions key contains an array of the elements of the version string for easy comparison.

redis.print()

A handy callback function for displaying return values when testing. Example:

Multi-word commands

To execute redis multi-word commands like SCRIPT LOAD or CLIENT LIST pass the second word as first parameter:

client.duplicate([options][, callback])

Duplicate all current options and return a new redisClient instance. All options passed to the duplicate function are going to replace the original option. If you pass a callback, duplicate is going to wait until the client is ready and returns it in the callback. If an error occurs in the meanwhile, that is going to return an error instead in the callback.

One example of when to use duplicate() would be to accommodate the connection- blocking redis commands BRPOP , BLPOP , and BRPOPLPUSH . If these commands are used on the same Redis client instance as non-blocking commands, the non-blocking ones may be queued up until after the blocking ones finish.

Another reason to use duplicate() is when multiple DBs on the same server are accessed via the redis SELECT command. Each DB could use its own connection.

client.sendCommand(command_name[, [args][, callback]])

All Redis commands have been added to the client object. However, if new commands are introduced before this library is updated or if you want to add individual commands you can use sendCommand() to send arbitrary commands to Redis.

All commands are sent as multi-bulk commands. args can either be an Array of arguments, or omitted / set to undefined.

redis.addCommand(command_name)

Calling addCommand will add a new command to the prototype. The exact command name will be used when calling using this new command. Using arbitrary arguments is possible as with any other command.

client.connected

Boolean tracking the state of the connection to the Redis server.

client.command_queue_length

The number of commands that have been sent to the Redis server but not yet replied to. You can use this to enforce some kind of maximum queue depth for commands while connected.

client.offline_queue_length

The number of commands that have been queued up for a future connection. You can use this to enforce some kind of maximum queue depth for pre-connection commands.

Commands with Optional and Keyword arguments

This applies to anything that uses an optional [WITHSCORES] or [LIMIT offset count] in the redis.io/commands documentation.

Example

Performance

Much effort has been spent to make Node Redis as fast as possible for common operations.

Debugging

To get debug output run your Node Redis application with NODE_DEBUG=redis .

This is also going to result in good stack traces opposed to useless ones otherwise for any async operation. If you only want to have good stack traces but not the debug output run your application in development mode instead ( NODE_ENV=development ).

Good stack traces are only activated in development and debug mode as this results in a significant performance penalty.

Comparison:

Standard stack trace:

Debug stack trace:

Contributing

License

This repository is licensed under the «MIT» license. See LICENSE.

Источник

#include <reply.hpp>

Public Types

enum   type {
  error = __CPP_REDIS_REPLY_ERR,
bulk_string = __CPP_REDIS_REPLY_BULK,
simple_string = __CPP_REDIS_REPLY_SIMPLE,
null = __CPP_REDIS_REPLY_NULL,

  integer = __CPP_REDIS_REPLY_INT,
array = __CPP_REDIS_REPLY_ARRAY

}
 
enum   string_type { error = __CPP_REDIS_REPLY_ERR,
bulk_string = __CPP_REDIS_REPLY_BULK,
simple_string = __CPP_REDIS_REPLY_SIMPLE
}
 

Public Member Functions

  reply (void)
 
  reply (const std::string &value, string_type reply_type)
 
  reply (int64_t value)
 
  reply (const std::vector< reply > &rows)
 
  ~reply (void)=default
  dtor
 
  reply (const reply &)=default
  copy ctor
 
reply &  operator= (const reply &)=default
  assignment operator
 
bool  is_array (void) const
 
bool  is_string (void) const
 
bool  is_simple_string (void) const
 
bool  is_bulk_string (void) const
 
bool  is_error (void) const
 
bool  is_integer (void) const
 
bool  is_null (void) const
 
bool  ok (void) const
 
bool  ko (void) const
 
  operator bool (void) const
 
const std::string &  error (void) const
 
const std::vector< reply > &  as_array (void) const
 
const std::string &  as_string (void) const
 
int64_t  as_integer (void) const
 
void  set (void)
 
void  set (const std::string &value, string_type reply_type)
 
void  set (int64_t value)
 
void  set (const std::vector< reply > &rows)
 
reply &  operator<< (const reply &reply)
 
type  get_type (void) const
 

cpp_redis::reply is the class that wraps Redis server replies. That is, cpp_redis::reply objects are passed as parameters of commands callbacks and contain the server’s response.

◆ string_type

specific type of replies for string-based replies

◆ type

type of reply, baed on redis server standard replies

◆ reply() [1/4]

cpp_redis::reply::reply ( void  )

default ctor (set a null reply)

◆ reply() [2/4]

cpp_redis::reply::reply ( const std::string &  value,
string_type  reply_type 
)

ctor for string values

Parameters
value string value
reply_type of string reply

◆ reply() [3/4]

cpp_redis::reply::reply ( int64_t  value )

ctor for int values

Parameters

◆ reply() [4/4]

cpp_redis::reply::reply ( const std::vector< reply > &  rows )

ctor for array values

Parameters
Returns
current instance

◆ as_array()

const std::vector<reply>& cpp_redis::reply::as_array ( void  ) const
Returns
the underlying array

◆ as_integer()

int64_t cpp_redis::reply::as_integer ( void  ) const
Returns
the underlying integer

◆ as_string()

const std::string& cpp_redis::reply::as_string ( void  ) const
Returns
the underlying string

◆ error()

const std::string& cpp_redis::reply::error ( void  ) const
Returns
the underlying error

◆ get_type()

type cpp_redis::reply::get_type ( void  ) const

◆ is_array()

bool cpp_redis::reply::is_array ( void  ) const
Returns
whether the reply is an array

◆ is_bulk_string()

bool cpp_redis::reply::is_bulk_string ( void  ) const
Returns
whether the reply is a bulk string

◆ is_error()

bool cpp_redis::reply::is_error ( void  ) const
Returns
whether the reply is an error

◆ is_integer()

bool cpp_redis::reply::is_integer ( void  ) const
Returns
whether the reply is an integer

◆ is_null()

bool cpp_redis::reply::is_null ( void  ) const
Returns
whether the reply is null

◆ is_simple_string()

bool cpp_redis::reply::is_simple_string ( void  ) const
Returns
whether the reply is a simple string

◆ is_string()

bool cpp_redis::reply::is_string ( void  ) const
Returns
whether the reply is a string (simple, bulk, error)

◆ ko()

bool cpp_redis::reply::ko ( void  ) const
Returns
true if function is an error

◆ ok()

bool cpp_redis::reply::ok ( void  ) const
Returns
true if function is not an error

◆ operator bool()

cpp_redis::reply::operator bool ( void  ) const

convenience implicit conversion, same as !is_null() / ok()

◆ operator<<()

reply& cpp_redis::reply::operator<< ( const reply &  reply )

for array replies, add a new row to the reply

Parameters
reply new row to be appended
Returns
current instance

◆ set() [1/4]

void cpp_redis::reply::set ( void  )

set reply as null

◆ set() [2/4]

void cpp_redis::reply::set ( const std::string &  value,
string_type  reply_type 
)

set a string reply

Parameters
value string value
reply_type of string reply

◆ set() [3/4]

void cpp_redis::reply::set ( int64_t  value )

set an integer reply

Parameters

◆ set() [4/4]

void cpp_redis::reply::set ( const std::vector< reply > &  rows )

set an array reply

Parameters

The documentation for this class was generated from the following file:

  • includes/cpp_redis/core/reply.hpp

Понравилась статья? Поделить с друзьями:
  • Received error when trying to advertise server on master server response was not valid json
  • Redis error moved
  • Received error from kdc 1765328360 preauthentication failed
  • Receipt is already open эвотор ошибка
  • Recaptcha validate error перевод