Programabilitate Atomică în Redis: Scripting Lua (EVALSHA) și Redis Functions (FCALL) în Redis & In-Memory Data Store

Ghid complet pentru logica de calcul pe server în Redis: executarea atomica a scripturilor Lua cu EVALSHA și trecerea modernă la Redis Functions (FUNCTION LOAD și FCALL) pentru cod compilat și replicat nativ.

Sintaxă comandă
FUNCTION LOAD '#!lua name=mylib ...' | FCALL myfunc 1 key arg | EVALSHA sha 1 key arg

Blocul tradițional de tranzacții Redis (MULTI / EXEC) este un simplu container secvențial: comenzile sunt puse într-o coadă și executate atomic, dar nu permit fluxuri condiționate de tip IF/ELSE bazate pe rezultatul unei comenzi anterioare din aceeași tranzacție.

Pentru a rula logică de afaceri complexă direct pe server, fără round-trip-uri lente de rețea și cu garanție de atomicitate absolută (nicio altă comandă a unui alt client nu poate interveni la mijloc), Redis include un motor încorporat de Lua.

Trecerea de la Scripting Lua la Redis Functions (Redis 7+)
-- Codul unei biblioteci Lua moderne pentru Redis Functions:
#!lua name=gestiune_stoc
redis.register_function('scade_stoc', function(keys, args)
    local cheie_produs = keys[1]
    local cantitate_ceruta = tonumber(args[1])

    local stoc_curent = tonumber(redis.call('GET', cheie_produs) or '0')

    if stoc_curent >= cantitate_ceruta then
        redis.call('DECRBY', cheie_produs, cantitate_ceruta)
        return { 1, stoc_curent - cantitate_ceruta } -- Succes, stoc rămas
    else
        return { 0, stoc_curent } -- Eșec: stoc insuficient
    end
end)

Încărcarea și Apelarea unei Funcții Redis

# 1. Încărcăm funcția pe server (stocată permanent în metadate și replicată la replici):
FUNCTION LOAD "#!lua name=gestiune_stoc \n redis.register_function('scade_stoc', function(keys, args) local k = keys[1]; local q = tonumber(args[1]); local s = tonumber(redis.call('GET', k) or '0'); if s >= q then redis.call('DECRBY', k, q); return {1, s - q}; else return {0, s}; end end)"

# 2. Inițializăm un stoc de test:
SET produs:laptop 10

# 3. Apelăm funcția prin FCALL:
# Sintaxă: FCALL    ... 
FCALL scade_stoc 1 produs:laptop 3
# Răspuns:
# 1) (integer) 1  (operațiune reușită)
# 2) (integer) 7  (stoc rămas)

FCALL scade_stoc 1 produs:laptop 15
# Răspuns:
# 1) (integer) 0  (eșec: stoc insuficient)
# 2) (integer) 7  (stocul a rămas neatins)

De Ce Redis Functions Sunt Superioare Scripturilor EVAL/EVALSHA?

  • Persistență Nativă: Funcțiile sunt incluse direct în fișierele de snapshot RDB și jurnalele AOF, fiind restaurate automat la repornire.
  • Management ca la Baze de Date: Codul este partajat de toți clienții fără a forța fiecare aplicație să trimită hash-ul SHA al scriptului la pornire.
  • Modularitate și Versiuni: Funcțiile sunt grupate în biblioteci numite (libraries), facilitând deployment-ul în CI/CD.