Rest-hooks en Siu-Guarani Gestión

hola Estimadas/os!
Estamos probando la interface entre Siu-Guarani y Siu-SQ
https://documentacion.siu.edu.ar/wiki/SIU-Guarani/version3.22.0/interfaces/sanaviron
y tenemos una consulta respecto a la conexión con Redis en
https://documentacion.siu.edu.ar/wiki/SIU-Guarani/Version3.22.0/interfaces/rest-hooks
ya que tenemos una instalación de Redis en otro server
Entonces al configurar en Guarani Gestión
<path proyecto Gestión>/instalacion/resthooks.ini
;resthooks.ini
resthooks_activo = 1
[redis_config]
host =
port =

neecsitamos poner ademas
bd=nro de base de redis
usuario=
passs=

hicimos una prueba poniendo algo como esto
host = “keystore-ejemplo.unc.edu.ar”
port = “6379?baseauth[user]=default&auth[pass]=***********&database=16”

pero no funcionó

saludos
Lucas

Ir a la issue

Hola Lucas
Esto les sucede para version guarni 3.22 ? saludos!

hola Sebastián!
Si, lo estamos probando en la versión 3.22.0.14

saludos

Hola @lmanjarres

Vos necesitas algo como esto del Backend, no?

Saludos.

hoa Leonel!
Si, pero usando un redis existente en otro servidor (con password y una base que no es la 0 ó 1)
https://gitlab.siu.edu.ar/siu/rest-hooks/-/blob/develop/README.md?ref_type=heads#redis
Acá menciona la solución de usar uno local. Por ahora lo hemos implementado de esa manera en nuestro espacio de pruebas

saludos
Lucas

Hola @lmanjarres

Si, quizás lo mas sano por ahora seria tener otro contenedor de redis en otro puerto:

docker run --name some-redis -p6379:6379 -d redis

Ya que no veo que permita configurar una conexión a una DB:

;resthooks.ini
resthooks_activo = 1
[redis_config]
host = <host>
port = <puerto>

Saludos.

hola Leonel!
Vos decis que solo para este caso deberíamos setear un redis con una única base y sin pass?

saludos
Lucas

Hola @lmanjarres

Al menos que veamos que otras opciones se pueden pasar.
Esto de Rest Hooks se utiliza en src/SIU/Guarani/RestHooks/RestHookSanaviron.php para la comunicación en SQ, en la función getRestMessenger vas a ver parte de la configuración que se le pasa a la clase RestMessenger.php. Podes ver las funciones del estilo public function setXxx (ej: public function setRedisConfig($host)), quizás encuentres alguna donde se puedan pasar los parámetros de conexión a la DB.

Nosotros usamos el esquema rest_hooks dentro de la DB de Guaraní, en el mismo se crean solo tres tablas: messages, phinxlog y requests. Eso se configura en src/SIU/Guarani/RestHooks/RestHookSanaviron.php función getRestMessenger.

Saludos.

hola Leonel!
buena data!
Nos fijamos allí y probamos como nos va
saludos
Lucas

Muchas Gracias Leonel por la información!
Efectivamente logramos hacer funcionar el RestHook mediante el uso de un Redis fuera del nodo de Guarani. Como nos dijiste lo logramos haciendo modificaciones a la función getRestMessenger del archivo src/SIU/Guarani/RestHooks/RestHookSanaviron.php.
A continuación dejo la configuración de esa función para los que la deseen:

public static function getRestMessenger()
    {
        if (! isset(self::$rhlib)) {
            $lib = new RestMessenger();

                        $lib->setMessageEncoding('iso-8859-1');

            $restHooksIni = static::getConfigRestHooks();
            $redisConf = $restHooksIni['redis_config'];

            //Modificacion para recibir User,Password y BD
            //Construccion de URI Redis
            $redisServer = "redis://";

            if (!empty($redisConf['user']) && !empty($redisConf['password'])) {
                $redisServer .= $redisConf['user'] . ":" . $redisConf['password'] . "@";
            } elseif (!empty($redisConf['password'])) {
                // Si no hay user, pero si password (forma comun en Redis)
                $redisServer .= ":" . $redisConf['password'] . "@";
            }

            $redisServer .= $redisConf['host'] . ":" . $redisConf['port'];

            if (isset($redisConf['database'])) {
                $redisServer .= "/" . $redisConf['database'];
            }

            if (isset($restHooksIni['resthooks_activo']) && $restHooksIni['resthooks_activo'] == 1) {
                $lib->setMode(RestMessenger::MODE_ENQUEUE);
                $lib->setInitializerMethod("\\SIU\\Guarani\\RestHooks\\RestHookSanaviron::getRestMessenger");
                $lib->setMaxRetries(static::MAX_RETRIES);
                $lib->setConfig($redisServer);
            } else {
                // si no esta activo resthook se envia directamente sin reintentos
                $lib->setConfig($redisServer);
                $lib->setMode(RestMessenger::MODE_DIRECT);
            }

            $defBase = static::getConfigDB();

            $backend = new Postgres([
                'dbname'    => $defBase['base'],
                'host'      => $defBase['profile'],
                'port'      => $defBase['puerto'],
                'username'  => $defBase['usuario'],
                'password'  => $defBase['clave'],
                'schema'    => static::SCHEMA_DB
            ]);

            $lib->setBackend($backend);

                        $apiRestConf = static::getConfigApiRest();

            $topic = $lib->createTopic('post_suscripciones_novedades');
            $lib->addTopic($topic);
            $listener = self::listenerPostSuscripcionesNovedades($topic, $apiRestConf);
            $lib->addListener($listener);

                        $topic = $lib->createTopic('post_servicios');
            $lib->addTopic($topic);
            $listener = self::listenerPostServicios($topic, $apiRestConf);
            $lib->addListener($listener);

                        $topic = $lib->createTopic('post_solicitudes_consumos_externos');
            $lib->addTopic($topic);
            $listener = self::listenerPostSolicitudesConsumosExternos($topic, $apiRestConf);
            $lib->addListener($listener);

            $lib->logToFile(static::getRestLogDirectory()."/rest-hooks.log");

            self::$rhlib = $lib;
        }

        return self::$rhlib;
    }

El cambio mas significativo es en la variable redisServer para lograr armar la conexion con el servidor Redis de la forma:

redis://user:password@host:port/database

Saludos, muchas gracias

Gracias por el aporte @ebenitez

Buen dia!
Si bien este tema ya fue solucionado me parecio apropiado realizar este aporte ya que es del mismo tema (Gestion - Redis)

El problema surge al configurar Guarani Gestion para que utilice redis (corriendo en un servidor externo) como manejador de sesiones.

Se configuro el php.ini para que use redis:

[Session] 
#session.save_handler = files
session.save_handler = redis
session.save_path = "tcp://<servidor_redis_externo>:<puerto>?auth[user]=default&auth[pass]=*******&database=<nro_base>"

Con esta configuracion se podia iniciar sesion y navegar correctamente. El problema surgia en ciertos tramites, arrojaba error y no se realizaba el tramite, por ejemplo en el tramite “Actualizar Tramites de Certificacion”, al intengar cambiar el estado de un egresado, arrojaba el siguiente error:

Luego de probar diferentes cosas dimos con la solucion para este problema y entendimos el por que del mismo.

El problema consistia basicamente en que si dos peticiones para la misma sesion a redis llegaban en simultaneo o muy juntas, se pisaban y se perdian datos, en este caso vemos que el error dice “no se encuentra la lista de efs activos”. La solucion fue la siguiente:

  1. Agregar un manejador de sesiones redis en toba:

    • En la ruta: /mnt/guarani/gestion/vendor/siu-toba/framework/php/nucleo/lib/session_handlers
    • Archivo agregado: toba_session_redis_handler.php
    • Contenido:

    <?php
    class toba_session_redis_handler extends toba_session_handler
    {
    protected $default_settings= array(
    'session.save_handler' => 'redis'
    );
    functionconstruct()
    {
    parent::
    construct();
    $current = \ini_get('session.save_path');
    if (!empty($current)) {
    $this->default_settings['session.save_path'] = $current;
    }
    }
    }
    ?>

    Esto por que notamos que existen clases para files y memcached, pero no para redis en cuestion.

  2. La otra parte de la solucion, que soluciona especificamente el problema de perdida de informacion por peticiones simultaneas o muy juntas, consiste en agregar tambien en el php.ini:
    redis.session.locking_enabled = 1
    redis.session.lock_wait_time = 1000
    redis.session.lock_retries = -1
    Esto basicamente lo que hace es que si una request usa una sesion, esa sesion se bloquea hasta que termina la operacion y si otra request intenta usar tambien esa sesion, al estar bloqueada, esperara el tiempo seteado (seguira intentandola usar, por eso el -1 el lock_retries), si pasado ese segundo no se libera el lock y la sesion sigue bloqueada, ahi dejaria de intentar.

Con estas configuraciones logramos que el error dejara de aparecer. Si bien fue realizado en un entorno de laboratorio y aun falta seguir testeando, consideramos que es un gran avance ya que el error dejo de aparecer y nos parecio bien compartirlo en la comunidad.

Gracias por el aporte @Juan_Pablo_Lambertuc

Actualizo! No es necesario realizar el punto 1 (Agregar un manejador de sesiones redis en toba).
Se probo eliminando este manejador y solo dejar la configuarcion del punto 2 (configuracion del php.ini) y sigue funcionando correctamente.