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: