Est-il possible d’appeler les fonctions Lua définies dans d’autres scripts Lua dans Redis?

J’ai essayé de déclarer une fonction sans le mot clé local, puis d’appeler cette fonction à partir d’un autre script, mais cela me donne une erreur lorsque je lance la commande.

test = function () return 'test' end # from some other script test() 

Modifier:

Je ne peux pas croire que je n’ai toujours pas de réponse à cela. Je vais inclure plus de détails sur ma configuration.

J’utilise noeud avec le paquetage redis-scripto pour charger les scripts dans redis. Voici un exemple.

 var Scripto = require('redis-scripto'); var scriptManager = new Scripto(redis); scriptManager.loadFromDir('./lua_scripts'); var keys = [key1, key2]; var values = [val]; scriptManager.run('run_function', keys, values, function(err, result) { console.log(err, result) }) 

Et les scripts Lua.

 -- ./lua_scripts/dict_2_bulk.lua -- turns a dictionary table into a bulk reply table dict2bulk = function (dict) local result = {} for k, v in pairs(dict) do table.insert(result, k) table.insert(result, v) end return result end -- run_function.lua return dict2bulk({ test=1 }) 

Lance l’erreur suivante.

 [Error: ERR Error running script (call to f_d06f7fd783cc537d535ec59228a18f70fccde663): @enable_ssortingct_lua:14: user_script:1: Script attempted to access unexisting global variable 'dict2bulk' ] undefined 

Avis important: Voir la réponse de Josiah ci-dessous. Ma réponse s’avère être fausse ou du moins incomplète . Ce qui me rend très heureux bien sûr, cela rend Redis d’autant plus flexible.

Ma réponse incorrecte / incomplète:

Je suis tout à fait sûr que ce n’est pas possible. Vous n’êtes pas autorisé à utiliser des variables globales (lisez la documentation ), et le script lui-même obtient une scope locale et temporaire par le moteur Redis Lua.

Les fonctions de Lua définissent automatiquement un drapeau ‘d’écriture’ en coulisse si elles effectuent une action d’écriture. Cela commence une transaction. Si vous appelez Lua en cascade, la comptabilité à Redis deviendrait très lourde, surtout lorsque la cascade est exécutée sur un esclave Redis. C’est pourquoi EVALSHA et EVALSHA sont pas intentionnellement disponibles en tant EVALSHA Redis valides dans un script Lua. Il en va de même pour appeler une fonction Lua ‘déjà chargée’ que vous essayez de faire. Que se passerait-il si l’esclave était redémarré entre le chargement du premier script et l’exécuteur du second script?

Ce que nous faisons pour surmonter cette limitation:

N’utilisez pas EVAL , utilisez uniquement SCRIPT LOAD et EVALSHA . Rangez le SHA1 dans un ensemble de hachage redis.

Nous avons automatisé cette opération dans notre système de gestion des versions. Ainsi, un script Lua dédié obtient automatiquement la sum de contrôle SHA1 stockée dans le maître Redis, dans un ensemble de hachage, avec un nom logique. Les clients ne peuvent pas utiliser EVAL (sur un esclave; nous avons désactivé EVAL + LOAD dans la configuration). Mais le client peut demander le SHA1 pour la prochaine étape. Presque toutes nos fonctions Lua renvoient un SHA1 pour le prochain appel.

J’espère que ça aide, TW

Je vais être contraire à la réponse acceptée, car la réponse acceptée est fausse.

Bien que vous ne puissiez pas définir explicitement les fonctions nommées, vous pouvez appeler n’importe quel script que vous pouvez appeler avec EVALSHA . Plus spécifiquement, tous les scripts Lua que vous avez explicitement définis via SCRIPT LOAD ou implicitement via EVAL sont disponibles dans l’espace de noms Lua global à f_ (jusqu’à / sauf si vous appelez SCRIPT FLUSH ), que vous pouvez appeler à tout moment.

Le problème que vous rencontrez est que les fonctions sont définies comme ne prenant aucun argument et que les tables KEYS et ARGV sont en fait des globales. Donc, si vous voulez pouvoir communiquer entre les scripts Lua, vous devez soit ARGV tables KEYS et ARGV , soit utiliser l’espace de clé Redis standard pour la communication entre vos fonctions.

 127.0.0.1:6379> chargement du script "return {KEYS [1], ARGV [1]}"
 "d006f1a90249474274c76f5be725b8f5804a346b"
 127.0.0.1:6379> eval "return f_d006f1a90249474274c76f5be725b8f5804a346b ()" 1 "bonjour" "monde"
 1) "bonjour"
 2) "monde"
 127.0.0.1:6379> eval "KEYS [1] = 'blah!'; Retournez f_d006f1a90249474274c76f5be725b8f5804a346b ()" 1 "hello" "world"
 1) "blah!"
 2) "monde"
 127.0.0.1:6379>

Tout cela étant dit, ceci est en totale violation des spécifications et il est tout à fait possible de cesser de fonctionner de manière étrange si vous tentez de l’exécuter dans un scénario de cluster Redis.

Parce que je ne suis pas du genre à partir assez bien seul, j’ai construit un paquet qui permet une sémantique d’appel interne simple. Le paquet (pour Python) est disponible sur GitHub .

En résumé, il utilise ARGV comme stack d’appel, traduit les références KEYS / ARGV en _KEYS et _ARGV , utilise Redis en tant que mappage de hachage nom -> en interne et traduit CALL.(, ) en un tableau annexe + appel Redis lookup + appel de fonction Lua.

Le fichier METHOD.txt décrit ce qui se passe et toutes les expressions régulières que j’ai utilisées pour traduire les scripts Lua sont disponibles dans lua_call.py . N’hésitez pas à réutiliser ma sémantique.

L’utilisation du registre de fonctions rend très peu probable le fonctionnement de ce dernier dans un cluster Redis ou toute autre configuration multi-partitions, mais pour les applications à maître unique, cela devrait fonctionner dans un avenir prévisible.