Redis Tutorial 0/42 lessons ~6 min read Lesson 18

    Lua Scripting

    Lua scripts run atomically on the Redis server — read, branch, and write in one execution without other commands interleaving.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Lua scripts run atomically on the Redis server — read, branch, and write in one execution without other commands interleaving. Rate limiters, safe lock release, and conditional transfers belong in Lua, not split across multiple round trips.

    EVAL runs script inline; EVALSHA uses SHA1 digest after SCRIPT LOAD. Scripts should be deterministic and fast — a slow script blocks the entire event loop.

    Redis 7 function libraries offer an alternative, but EVAL remains the production standard for atomic custom logic.

    Understanding the topic

    Key concepts

    • EVAL script numkeys key [key ...] arg [arg ...].
    • redis.call() — invoke commands; errors abort script.
    • redis.pcall() — errors as return values.
    • Scripts cached by SHA; EVALSHA on cache hit.
    • Entire script atomic — no partial visibility.
    • No long loops — blocks single thread.

    Step-by-step explanation

    1. Client sends EVAL with script body and keys/args.
    2. Redis loads Lua interpreter if needed.
    3. Script executes with KEYS[] and ARGV[] arrays.
    4. All redis.call operations run without interruption.
    5. Result returned as bulk reply; script cached for EVALSHA.

    Syntax reference

    Common commands

    • KEYS[1] — pass all key names via KEYS array for cluster slot safety.
    • Keep scripts short.
    • Load once with SCRIPT LOAD in deploy.
    bash
    # Atomic rate limit: max 60 req/min
    EVAL "
    local c = redis.call('INCR', KEYS[1])
    if c == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end
    return c
    " 1 rate:user:42 60

    Informative example

    Safe lock release — delete only if token matches:

    bash
    EVAL "
    if redis.call('GET', KEYS[1]) == ARGV[1] then
    return redis.call('DEL', KEYS[1])
    else return 0 end
    " 1 lock:order:99 my-uuid-token

    Never DEL lock without checking token — another process may have acquired after yours expired.

    Real-world use

    Real-world use cases

    • Sliding window rate limiter.
    • Compare-and-delete lock release.
    • Conditional balance transfer with check.
    • Atomic ZADD + EXPIRE + ZREMRANGEBYRANK trim.
    • Idempotent claim processing with SET NX in script.

    Best practices

    • Pass keys in KEYS array for Cluster compatibility.
    • Preload scripts; use EVALSHA in hot path.
    • Version scripts in application config.
    • Avoid unbounded loops and KEYS inside scripts.
    • Test scripts in staging with production key patterns.
    • Keep scripts under 1ms execution target.

    Common mistakes

    • Non-deterministic scripts (TIME, RANDOMKEY) break replication.
    • Using GET+DEL in app without Lua — race on lock release.
    • Huge scripts blocking event loop.
    • Hardcoding keys in script body instead of KEYS array.

    Advanced interview questions

    Q1BeginnerWhy Lua in Redis?
    Atomic read-modify-write with branching on server.
    Q2BeginnerEVAL vs MULTI?
    Lua can branch on reads; MULTI queues fixed commands only.
    Q3IntermediateSafe lock unlock?
    Lua: DEL only if GET equals unique token.
    Q4IntermediateEVALSHA benefit?
    Avoids sending full script body each call after SCRIPT LOAD.
    Q5AdvancedLua on Redis Cluster?
    All keys referenced must hash to same slot — use hash tags {user}:lock.

    Summary

    Lua = atomic custom logic on server.

    Ready to mark this lesson complete?Track your journey across the entire course.