Go Redis Lua Scripting
redis.Script
go-redis supports Lua scripting with redis.Script, for example, the following script implements INCRBY
command in Lua using GET
and SET
commands:
var incrBy = redis.NewScript(`
local key = KEYS[1]
local change = ARGV[1]
local value = redis.call("GET", key)
if not value then
value = 0
end
value = value + change
redis.call("SET", key, value)
return value
`)
You can then run the script like this:
keys := []string{"my_counter"}
values := []interface{}{+1}
num, err := incrBy.Run(ctx, rdb, keys, values...).Int()
Internally, go-redis uses EVALSHA to execute the script and fallbacks to EVAL if the script does not exist.
You can find the example above at GitHub. For a more realistic example, check redis_rate which implements a leacky bucket rate-limiter.
Lua and Go types
Underneath, Lua's number
type is a float64
number that is used to store both ints and floats. Because Lua does not distinguish ints and floats, Redis always converts Lua numbers into ints discarding the decimal part, for example, 3.14
becomes 3
. If you want to return a float value, return it as a string and parse the string in Go using Float64 helper.
Lua return | Go interface{} |
---|---|
number (float64) | int64 (decimal part is discarded) |
string | string |
false | redis.Nil error |
true | int64(1) |
{ok = "status"} | string("status") |
{err = "error message"} | errors.New("error message") |
{"foo", "bar"} | []interface{}{"foo", "bar"} |
{foo = "bar", bar = "baz"} | []interface{}{} (not supported) |
Debugging Lua scripts
The easiest way to debug your Lua scripts is using redis.log
function that writes the message to the Redis log file or redis-server
output:
redis.log(redis.LOG_NOTICE, "key", key, "change", change)
If you prefer a debugger, check Redis Lua scripts debugger.
Passing multiple values
You can use for
loop in Lua to iterate over the passed values, for example, to sum the numbers:
local key = KEYS[1]
local sum = redis.call("GET", key)
if not sum then
sum = 0
end
local num_arg = #ARGV
for i = 1, num_arg do
sum = sum + ARGV[i]
end
redis.call("SET", key, sum)
return sum
The result:
sum, err := sum.Run(ctx, rdb, []string{"my_sum"}, 1, 2, 3).Int()
fmt.Println(sum, err)
// Output: 6 nil
Loop continue
Lua does not support continue
statements in loops, but you can emulate it with a nested repeat
loop and a break
statement:
local num_arg = #ARGV
for i = 1, num_arg do
repeat
if true then
do break end -- continue
end
until true
end
Error handling
By default, redis.call
function raises a Lua error and stops program execution. If you want to handle errors, use redis.pcall
function which returns a Lua table with err
field:
local result = redis.pcall("rename", "foo", "bar")
if type(result) == 'table' and result.err then
redis.log(redis.LOG_NOTICE, "rename failed", result.err)
end
To return a custom error, use a Lua table:
return {err = "error message goes here"}
Monitoring Performance
Monitoring the performance of a Redis database is crucial for maintaining the overall health, efficiency, and reliability of your system. Proper performance monitoring helps identify and resolve potential issues before they lead to service disruptions or performance degradation.
Uptrace is a DataDog competitor that supports distributed tracing, metrics, and logs. You can use it to monitor applications and troubleshoot issues.
Uptrace comes with an intuitive query builder, rich dashboards, alerting rules with notifications, and integrations for most languages and frameworks.
Uptrace can process billions of spans and metrics on a single server and allows you to monitor your applications at 10x lower cost.
In just a few minutes, you can try Uptrace by visiting the cloud demo (no login required) or running it locally with Docker. The source code is available on GitHub.
See also
The following guides can help you get started with Lua scripting in Redis: