Ir al contenido principal

Mantén la integridad de tus mensajes JMS con WSO2 EI | Tutorial

JMS

Uno de los elementos principales de WSO2 Enterprise Integrator son los servicios proxy, que actúan como interlocutores entre un sistema externo que realiza la llamada (cliente) y el servicio final al cual va destinada dicha llamada (backend).

De esta forma, situándonos en medio tanto de la petición como en la respuesta, podremos realizar distintas operaciones (transformación, auditoría, securización, etc) sin necesidad de modificar el servicio destino.

Los proxy services pueden ser de múltiples tipos, en función de cómo los definamos a través de su atributo ‘transport’.

JMS Consumer y JMS Publisher

Los servicios proxy que definamos en su atributo ‘transport’ como JMS (Java Message Service), será lo que consideramos un JMS Consumer. Es decir, un proxy service que estará a la escucha de los mensajes que lleguen a una determinada cola.

De esta forma podremos realizar una orquestación donde un sistema externo manda mensajes a una cola y el Enterprise Integrator estará pendiente de los mensajes que le llegan para reenviarlos a un servicio final. Esta es una forma común de realizar integraciones de sistemas de forma asíncrona.

En cambio, si en vez de recibir un mensaje proveniente de una cola, lo que hiciésemos fuese enviar un mensaje a una cola, estaríamos hablando de un JMS Publisher.

¿Pero qué pasa tras leer de una cola, si al intentar llamar al servicio final ocurre un error? ¿Cómo gestiona el Enterprise Integrator estos mensajes? Para ello hay diferentes soluciones y en este artículo trataremos algunas de ellas.

Transacciones JMS

¿Cómo funcionan? Configuraremos el Enterprise Integrator para que permita el uso de transacciones asociadas a la gestión de mensajes JMS. Con ello conseguiremos que, en el caso de que la respuesta tras enviar un mensaje JMS sea errónea, este no se pierda sino que sea redirigido a otra cola. Brindándonos la posibilidad de volver a realizar el envío.

Estas transacciones pueden ser locales, es decir, que solo intervenga una única cola. O distribuidas, en el caso de que intervengan distintas colas y el mensaje sea enviado a todas ellas.

Dead Letter Channel

Cuando hemos hablado de una cola intermedia, nos estábamos refiriendo en realidad a la cola ‘Dead Letter Channel’. Esta cola de creación automatizada por parte del gestor de mensajes, funcionará como almacén de aquellos mensajes que por circunstancias externas no han podido ser entregados correctamente.

Una vez en esta cola, podremos:

  • Borrar los mensajes,
  • Reintentar su envío,
  • Redirigirlos a otro servicio.

Transacción local con Java Message Service Consumer (JMS Consumer)

Para ver su correcto funcionamiento, vamos a realizar un sencillo ejemplo. En el cual crearemos un proxy service que actúe como JMS Consumer, este recibirá un mensaje a través de una cola y lo enviará a un servicio final. Utilizaremos el Message Broker de WSO2 como gestor de mensajes y colas. Con el cual además podremos ver como los mensajes erróneos son enviados a la cola Dead Letter Channel.

Configuración

Primero debemos habilitar la transaccionalidad modificando el fichero EI_HOME/conf/axis2/axis2.xml e incluyendo el parámetro transport.jms.SessionTransacted a true en cada connection factory configurado:

<transportReceiver name="jms" class="org.apache.axis2.transport.jms.JMSListener">
    <parameter name="myQueueConnectionFactory" locked="false">
      <parameter name="java.naming.factory.initial" locked="false">org.wso2.andes.jndi.PropertiesFileInitialContextFactory</parameter>
        <parameter name="java.naming.provider.url" locked="false">conf/jndi.properties</parameter>
        <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">QueueConnectionFactory</parameter>
        <parameter name="transport.jms.ConnectionFactoryType" locked="false">queue</parameter>
        <parameter name="transport.jms.SessionTransacted">true</parameter>
    </parameter>
</transportReceiver>

Diseño

Vamos a crear un proxy service sencillo que llama a un backend que siempre funcione. Este servicio tiene las siguientes características:

  • Utiliza un mediator call con la propiedad blocking a true. De esta forma mantenemos el mismo hilo y se puede llevar a cabo la transaccionalidad con éxito.
  • Utiliza la propiedad ‘SET_ROLLBACK_ONLY’ en la secuencia de fallo con el valor a true. De esta forma queremos indicar que la transacción debe ser revertida, y por tanto el mensaje será enviado al Dead Letter Channel.
  • Utiliza la propiedad ‘transport.jms.ContentType’ para indicar el tipo de mensaje que nos llegará por la cola.
<proxy xmlns="http://ws.apache.org/ns/synapse" name="LocalTransactionJMSConsumerProxy"
      startOnLoad="true" statistics="disable" trace="disable" transports="jms">
  <target>
      <inSequence>
        <call blocking="true">
            <endpoint>
              <http method="POST" uri-template="http://localhost:8280/services/echo.echoHttpSoap12Endpoint"/>
            </endpoint>
        </call>
        <log level="custom">
            <property name="Transaction Action" value="Committed"/>
            <property expression="$body" name="response"/>
        </log>
      </inSequence>
      <faultSequence>
        <property name="SET_ROLLBACK_ONLY" scope="axis2" value="true"/>
        <log level="custom">
            <property name="Transaction Action" value="Rollbacked"/>
        </log>
      </faultSequence>
  </target>
  <parameter name="transport.jms.ContentType">
      <rules xmlns="">
        <jmsProperty>contentType</jmsProperty>
        <default>application/soap+xml</default>
      </rules>
  </parameter>
  <description/>
</proxy>

Ejemplo

Para probar el correcto funcionamiento, nos adentraremos en la consola del Message Broker y publicaremos un mensaje en la cola  JMSTransactionProxy (esta cola habría sido creada automáticamente al crear el proxy service) y veremos en el log como se muestra el mensaje ‘Committed’ y el cuerpo de la respuesta.

Si queremos ver el funcionamiento del rollback podemos probar a enviar un mensaje XML mal formado. Y al publicar el mensaje, veremos en los logs el error del XML mal formado, el mensaje  Rollbacked y como en el Dead Letter Channel se muestra ese mensaje. El identificador del mensaje puedes verlo también en el log del Message Broker.

El patron de integracion Dead Letter Channel

El Dead Letter Channel no es una solución única de WSO2 sino que es por sí misma un patrón de integración. Y por tanto aplicable a través de cualquier gestor de mensajes y colas.

Por tanto teniendo como base este patrón, podemos implementarlo manualmente nosotros y así evitar la pérdida de mensajes. Esto lo podemos realizar sin necesidad de las transacciones JMS (Java Message Service).

Para ello, simplemente tendremos que añadir un message store mediator en la secuencia de error en el cual indicaremos a qué cola queremos redirigir los mensajes que fallan. Brindándonos así la posibilidad de tener distintas colas que utilizaremos como Dead Letter Channel para distintas integraciones.

<faultSequence>
  <log level="custom">
    <property name="Transaction Status" value="Not Delivery"/>
  </log>
  <store messageStore="customDLCMessageStore" />
</faultSequence>

Redelivery Policy

También podemos forzar al gestor de colas para que a la hora de realizar el envío del mensaje tenga en cuenta una política de reenvío. Esta configuración es distinta según el gestor de colas que vayamos a utilizar.

Para el Message broker lo configuraremos las propiedades en diversos sitios. Por un lado configuraremos el número máximo de intentos a realizar en el fichero EI_HOME/wso2/broker/conf/broker.xml, modificando la variable maximumRedeliveryAttempts.

<maximumRedeliveryAttempts>2</maximumRedeliveryAttempts>

Y para configurar el tiempo de espera máximo entre intentos, lo configuraremos a través de fichero EI_HOME/conf/jndi.properties y la propiedad redeliveryDelay.

amqp://admin:admin@clientID/carbon?redeliverydelay='15000'&brokerlist='tcp://localhost:5673'

Conclusión

Hemos podido ver como con WSO2 podemos mantener la integridad en el envío de mensajes y cómo nos provee de métodos que nos permitan llevarla fácilmente a cabo. Evitando de forma sencilla la pérdida de mensajes en nuestras integraciones.

Aparte de estos medios aquí indicados, basados en el protocolo JMS (Java Message Service)o en patrones de arquitectura, también tenemos que tener en cuenta que WSO2 nos provee de dos mediators: Message Store y Message Processor que nos pueden ayudar y mucho en aumentar la integridad de nuestras operaciones con colas.