jueves, 4 de febrero de 2021

WSO2 y Redis

Ya estuvimos hablando en un post anterior de WSO2 y el cache mediator. Hoy veremos una solución alternativa pero similar. En este caso utilizaremos Redis, que nos permitirá cachear la respuesta de un backend. 

Redis es un almacén de estructura de datos de valores de clave en memoria rápido y de código abierto. Básicamente una base de datos nosql de tipo clave y valor, muy popular entre los desarrolladores. Redis, permite el uso de diferentes tipos de datos: List, Sets, Hashes, etc. 

Nosotros nos basaremos únicamente en los pares clave-valor, los hashes. Y veremos su uso a través de un ejemplo, como siempre. En este ejemplo llamaremos a un backend y almacenaremos su respuesta asociado al identificador del objeto. Lo cual nos permitirá que al volver a llamar con el mismo identificador, devolver la respuesta anteriormente obtenida. 

Para empezar, usaremos un WSO2 EI 6.5.0. Con la versión standalone no es posible conectarse a Redis, para conseguirlo debemos hacer dos cosas:

  • Añadir la librería Jedis (2.10.2) en la carpeta ${WSO2_HOME}/lib y arrancar el servidor. 
  • Añadir el conector de Redis a través de la interfaz gráfica.  

El conector se puede obtener desde el WSO2 Store, y hay distintas versiones en función del producto que utilicemos. Hay que recordar que una vez después de añadirlo es necesario habilitarlo.


La forma más sencilla de utilizar Redis es como siempre utilizar docker, y para ello usaremos el siguiente comando:

docker run -p 6379:6379 --name redis -d redis

El uso del conector de Redis es similar al de otros conectores. Básicamente son custom mediators, que admiten múltiples propiedades y los cuales tienen nombres identificativos de las operaciones que realizan. 

Vamos a crear una API con varios recursos. En el primer recurso realizaremos los siguientes pasos:
  • Buscamos el identificador en Redis a través de la operación hExists. En la cual tenemos que incluir el volumen donde esta almacenado y su clave. 
  • Si existe la clave, utilizaremos la operación hGet con los mismos valores para recuperar el valor almacenado. 
  • Si no existe la clave, procederemos a llamar al backend. Posteriormente almacenaremos el valor a través de la operación hSet, en la cual indicaremos el volumen, la clave y el valor asociado. 
Además debemos tener en cuenta distintos aspectos del conector a tener en cuenta:
  • La primera vez que utilicemos el conector debemos invocar la operación init, la cual nos posibilitará la conexión a Redis. 
  • El resultado de la operación hExists se almacena en una propiedad de contexto denominada redisResponse. 
  • La operación hGet devuelve un valor true o false en base a si encuentra o no el resultado.
  • Debemos almacenar y restaurar el payload al utilizar la operación hSet para evitar devolver el resultado de la misma al cliente. 
<resource methods="GET" uri-template="/{bookId}">
    <inSequence>
        <property name="bookId" expression="$ctx:uri.var.bookId"/>
        <redis.init>
            <redisHost>localhost</redisHost>
            <redisPort>6379</redisPort>
            <redisTimeout>500</redisTimeout>
        </redis.init>
        <redis.hExists>
            <redisKey>Library</redisKey>
            <redisField>{$ctx:bookId}</redisField>
        </redis.hExists>
        <filter source="$ctx:redisResponse" regex="true">
            <then>
                <redis.hGet>
                    <redisKey>Library</redisKey>
                    <redisField>{$ctx:bookId}</redisField>
                </redis.hGet>
            </then>
            <else>
                <call>
                    <endpoint>
                        <http method="GET" uri-template="http://localhost:57001/book/{uri.var.bookId}"/>
                    </endpoint>
                </call>
                <enrich>
                    <source type="body" clone="false"/>
                    <target type="property" property="ORIGINAL_PAYLOAD"/>
                </enrich>
                <redis.hSet>
                    <redisKey>Library</redisKey>
                    <redisField>{$ctx:bookId}</redisField>
                    <redisValue>{$ctx:ORIGINAL_PAYLOAD}</redisValue>
                </redis.hSet>
                <enrich>
                    <source type="property" clone="false" property="ORIGINAL_PAYLOAD"/>
                    <target type="body"/>
                </enrich>
            </else>
        </filter>
        <property name="ContentType" scope="axis2" type="STRING" value="application/json"/>
        <respond/>
    </inSequence>
</resource>

A diferencia del cache mediator, con el conector de Redis podremos borrar un valor almacenado. Y esto es gracias a que el conector contiene múltiples operaciones. 

<resource methods="DELETE" uri-template="/{bookId}">
    <inSequence>
        <property name="bookId" expression="$ctx:uri.var.bookId"/>
        <redis.init>
            <redisHost>localhost</redisHost>
            <redisPort>6379</redisPort>
            <redisTimeout>500</redisTimeout>
        </redis.init>
        <redis.hDel>
            <redisKey>Library</redisKey>
            <redisFields>{$ctx:bookId}</redisFields>
        </redis.hDel>
        <respond/>
    </inSequence>
    <outSequence/>
    <faultSequence/>
</resource>

Este es un ejemplo muy básico, en nuestra integración podemos realizar diferentes llamadas y lógicas más complicadas para luego almacenar ese valor en base a un identificador. Esto nos puede llevar a mejorar mucho el rendimiento de nuestras integraciones. 

No hay comentarios:

Publicar un comentario