Hace un tiempo lancé una pregunta sobre programación Lua en Redis y compartí un trozo de código que me tenía dándole vueltas. Por si te lo perdiste, este es el script:

lua script

A simple vista es el clásico patrón “ping-pong”: una función llama a la otra, y la otra vuelve a llamar a la primera. Es el ejemplo de manual para enseñar recursividad y llamadas entre funciones, el que sale en la primera clase de cualquier curso.

Lo que esperas es que las dos funciones se llamen entre sí hasta el fin de los tiempos. En la mayoría de entornos eso acaba con el proceso colgado o topando contra algún límite del sistema, de esos soft o hard que pone el administrador para que nadie se lleve la máquina por delante.

En Redis pasa otra cosa. Redis te deja ejecutar Lua, lo que está muy bien porque puedes hacer cálculos y manipular datos dentro de la propia base de datos, sin ir y volver por la red. Pero no te lo deja hacer a pelo: el intérprete corre en un entorno acotado, con unas cuantas protecciones para que un script no se cargue la instancia, lo hagas queriendo o sin querer.

Así que al lanzar el script no hay bucle infinito ni servidor caído. Redis se huele el patrón y corta por lo sano. Esto es lo que pasa por dentro:

Redis lleva protecciones que reconocen la recursión del script. El entorno Lua acotado está pensado justo para detectar este tipo de bucles y pararlos antes de que el script se coma la CPU y la memoria de la máquina. Y lo hace pronto, no cuando ya te ha dejado la instancia de rodillas.

En concreto, aquí Redis marca la tabla como de solo lectura. Eso impide las modificaciones que llevarían a la recursión descontrolada, así que el script se queda sin la pieza que necesitaba para retroalimentarse y muere ahí mismo.

Esta es la respuesta exacta que devuelve Redis al ejecutar el script:

response from redis

Como ves en la captura, Redis devuelve un error: “Intento de modificar un script de tabla de solo lectura”. Es decir, ha pillado el intento de ejecutar una función recursiva que puede hacer daño y lo ha frenado antes de empezar. No es casualidad ni suerte: está pensado para que pase exactamente eso.

Esa forma de tratar los scripts Lua dice bastante de Redis como base de datos. Al cortar los bucles infinitos y los scripts que pueden hacer daño, la instancia sigue en pie y respondiendo aunque le metas cosas raras por delante. Que es lo que le pides a la pieza que tiene todo tu caché.

En producción esto se nota, y mucho, si tienes un servicio que no se puede permitir caerse. Puedes escribir tus scripts Lua sabiendo que hay una red debajo por si la lías. Y poder hacer operaciones complicadas dentro de la propia base de datos, sin sacar los datos fuera y sin que nada reviente, es de las cosas que más partido me han dado.

Detalles como este son los que me hacen fiarme de Redis. Manejar un script problemático sin dramas, devolviendo un error claro en vez de morirse, es justo lo que quieres de algo que va a estar corriendo meses sin que tú lo mires.

Otro punto para Redis, vamos.

¡Redis es una jodida maravilla! Se nota que me gusta, ¿verdad? 😄