Skip to content

Quickstart

Define a script

Define scripts at module level. They compile once, when the module is imported.

limits.py
from redis_lua_py import Key, redis, script


@script
def rate_limit(key: Key, limit: int, ttl: int) -> int:
    current = redis.incr(key)
    if current == 1:
        redis.expire(key, ttl)
    if current > limit:
        return -1
    return limit - current

The body is never executed by Python. It is read as source at import, compiled to Lua, and sent to Redis with EVALSHA.

A script defined inside a function recompiles on every call, and one defined through exec has no source to read and is refused.

Call it

from redis import Redis

from limits import rate_limit

client = Redis()
remaining = rate_limit(client, key="user:42", limit=10, ttl=60)

Importing the client as from redis import Redis leaves the name redis free for the script namespace, so the two never collide. If you want the client module itself, see When the client is imported too.

Scripts accept positional or keyword arguments; keyword is clearer at the call site and is what the errors suggest.

Read the Lua

Nothing is hidden:

print(rate_limit.lua)
-- rate_limit
-- Generated by redis-lua-py from limits.py:5. Do not edit.
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local ttl = tonumber(ARGV[2])
local current = redis.call('INCR', key)
if current == 1 then
  redis.call('EXPIRE', key, ttl)
end
if current > limit then
  return -1
end
return limit - current

More on the header, the SHA, and why the path is repo-relative in What it compiles to.

Test it

fakeredis runs the real Lua in process, so a behavioural test needs no server:

import fakeredis

from limits import rate_limit


def test_rate_limit_refuses_past_the_limit():
    client = fakeredis.FakeRedis()

    assert rate_limit(client, key="u:42", limit=2, ttl=60) == 1
    assert rate_limit(client, key="u:42", limit=2, ttl=60) == 0
    assert rate_limit(client, key="u:42", limit=2, ttl=60) == -1

See Testing your scripts for golden-Lua snapshots as well.

Next