En este tercer artículo de la serie Arquitecturas Event-Driven continuaremos ampliando los aspectos complejos y/o necesidades avanzas del uso de eventos y las características que pueda necesitar.
Lo recuerdo tal y como lo hice en el anterior artículo, si tienes alguna duda o no tienes algún concepto muy claro te aconsejo que leas el artículo parte 1 (ya que nos basaremos en él) y sobre todo porque daremos algunas cosas por supuestas.
Por otro lado, el artículo parte 2 es independiente de este ya que cubre otras necesidades, por lo que puedes decidir no leerlo, lo que si te aviso es que es que TODAS las necesidades pueden ser utilizadas de forma individual o en combinación.
Este artículo está dividido en 2 partes:
- Ampliación "2" de las Características de un Evento
1.1. Inmutabilidad
1.2. Expiración
1.3. Ubicación
1.4. Seguridad
1.5. Modos de Ejecución - Conclusiones
1. Ampliación "2" de las Características de un Evento
Continuamos con la explicación que deje a medias...
Nosotros consideraremos para este artículo las necesidades marcadas en negrita
- Organizativas
- Internacionalización
- Ordenación
- Inmutabilidad
- Expiración
- Ubicación
- Seguridad
- Modos de Ejecución
1.1. Inmutabilidad
Cuando hablamos de inmutabilidad nos referimos a que el contenido del evento NO se pueda cambiar, o mejor dicho NO se pueda dar el cambiar todo, ya que proporcionaría información incoherente y/o sufriría una manipulación...y nadie quiere eso.
- En la mayoría de los casos el evento NO se debería de modificar en ninguno de sus valores porque sería como cambiar la realidad de lo que ha pasado cuando ese evento se creo.
- Si se quiere cambiar alguno de sus atributos, esto siempre debe tener un motivo y este motivo debe ser por requerimiento de la funcionalidad.
- El payload suele ser uno de los elementos permitidos para cambiar, aunque normalmente no es la totalidad del campo, sino que es alguna de su partes o bien facilita la incorporación de información extra.
- El status si suele ser utilizado en un flujo de datos o bien una máquina de estados.
- Algún parámetro de fecha, con ello me refiero a pasar por un punto que requiera algún tipo tramitación y se añade la fecha en la que ha sido tratado.
- Cuidado: El hecho de enriquecer un evento y que este no esté controlado, puede generar otros eventos cada uno con parte de la información igual y otra parte diferente, por lo que se duda de cual es el bueno para consumir.
Ejemplos de uso
Nota : Todos los ejemplos de uso irán centrados en considerar el envío de un email con payload en formato JSON (de aquí en adelante EEPJ (Envío Email Payload JSON)) de esta forma podréis ver las diferencias "particulares" de cada caso. Tened en cuenta que estas propiedades pueden ser utilizadas en cada caso y que no se exige que sean exactamente como se representan en estos ejemplos.
- Ejemplo 1: "EEPJ con payload": Evento EEPJ en el que el payload se mantiene fijo desde el momento en que es añadido al evento, no debería de cambiar durante su "viaje".
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
}
- Ejemplo 2: "EEPJ con un payload parcial": Evento EEPJ en el que el paso del evento por ese punto sólo proporciona la inclusión de los campos "to" y "from" del email. Posteriormente se incorporará la otra información que falta.
Nota : Se presupone que el resto de campos una vez puestos son fijos
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
}
- Ejemplo 3: "EEPJ con un fecha actualizada": Evento EEPJ en el que el paso del evento actualiza un campo por ejemplo del tipo fecha "updateDate".
Nota : Cambiar cualquier otro campo podría generar una manipulación de lo que ocurrido.
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : ''
}
1.2. Expiración
Este aspecto hace alusión a la capacidad de poder "expirar" / "caducar" / "invalidar" la información que ya no interesa en base a alguno de sus criterios relacionados con la temporalidad.
Propuesta de criterios de temporalidad:
- Fecha de caducidad establecida
- Tiempo de creación + Tiempo de vida "útil" + Fecha actual
- Fecha de creación + Tiempo de vida "útil" + Fecha actual
- Cumplimiento de un ciclo de vida definido, ya sea por su propio estado, pos su situación dentro del flujo o bien por algún tipo de control sobre el evento (aprobación, validación, revisión, actualización) -> En estos casos la expiración tiene más una funcionalidad de filtro
Tenerlo en consideración suele ayudar a tener un funcionamiento óptimo al no dedicar recursos a tratar aquello que se considera innecesario
- Suele ser dependiente de la lógica de negocio por lo que cada caso debería de ser estudiado de forma independiente.
- Opcional
- Si no se define en el evento la información adecuada NO se podrá expirar su contenido.
- En algunos casos estos criterios de expiración pasan por eliminar los elementos que no cumplan el criterio de forma definitiva, en otros casos los elementos "expirados" son movidos o cambiados para ser tratados de otra forma (Planes "B").
- La evaluación de la expiración se puede hacer en el momento de procesamiento, pero se aconseja que se establezca de una tarea paralela que se dedique a realizarlo mientas está funcionado el procesamiento o mientas este se encuentra parado.
- Algunas consideraciones pueden ser :
- Establecer creationDateTime y disponer de un tiempo establecido en la lógica por la cual al compararlo con la fecha del momento actual.
- Establecer expirationTime como el tiempo en milisegundos e impedir su procesamiento a partir de un número.
Ejemplos de uso
Nota: Todos los ejemplos de uso irán centrados en considerar el envío de un email con payload en formato JSON (de aquí en adelante EEPJ (Envío Email Payload JSON)) de esta forma podréis ver las diferencias "particulares" de cada caso. Tened en cuenta que estas propiedades pueden ser utilizadas en cada caso y que no se exige que sean exactamente como se representan en estos ejemplos.
- Ejemplo 1: "EEPJ con expiración por fecha de creación": Eventos EEPJ en los que un criterio de expiración como rechazar todo lo que no ocurriera en el día de trabajo pensando que es el 30-12-2020 (durante sus 24h) dejaría fuera al evento con eventId 18
{
{
eventId : 25,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
},
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-29 04:36:58.999',
updateDate : ''
}
}
- Ejemplo 2: "EEPJ con expiración por expiration time": Eventos EEPJ en los que un criterio de expiración por tiempo de 5 minutos (300000 milisegundos) indicado en el evento podría llegar a dejar fuera a los 2 eventos si se ejecutara a las 23:45:00 del día 30-12-2020.
Nota : El expirationTime no requiere su uso junto a campos de fecha, de hecho puede ser utilizado en ese momento
{
{
eventId : 25,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153',
expirationTime : 300000
},
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-29 04:36:58.999',
updateDate : '',
expirationTime : 300000
}
}
- Ejemplo 3: "EEPJ con expiración por expiration time basado en milisegundos": Eventos EEPJ en los que un criterio de expiración por tiempo de 5 minutos (300000 milisegundos) podría afectar al expirationTime. Por ejemplo, se podría caducar aquellos eventos que superaran en 300000 milisegundos respecto al momento en el que se activa el proceso.
Criterio de tiempo utilizado :
Fecha GMT/UTC: sábado, 1 de febrero de 2020 9:30:00
Tiempo: sábado, 1 de febrero de 2020 10:30:00 GMT+01:00
Epoch: 1580549400
Epoch en milisegundos: 1580549400000
{
{
eventId : 25,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
expirationTime : 1580549400000
}
}
1.3. Ubicación
La ubicación hace referencia a localización de un elemento en un momento dado por lo que puede hacer referencias a:
- Continente
- País
- Provincia
- Municipio
- Geolocalización
- Rangos de IPs
- Localización en el espacio con : acelerómetros, etc.
- ...
Al igual que el punto de internacionalización, puede hacer referencia a muchas cosas y lo bueno es que estas cosas tendrán que venir definidas por negocio.
- Para ello se podrá añadir algún atributo a nivel del evento o bien a nivel de payload donde se haga referencia a lo que se quiere tratar.
- Últimamente debido a los diferentes conflictos y leyes políticas existentes entre países conviene analizar este punto con especial cuidado.
- El ámbito puede ser meramente informativo o bien ser utilizado para realizar algún tipo de filtrado (inclusivo o excluyente).
Ejemplos de uso
Nota : Todos los ejemplos de uso irán centrados en considerar el envío de un email con payload en formato JSON (de aquí en adelante EEPJ (Envío Email Payload JSON)) de esta forma podréis ver las diferencias "particulares" de cada caso. Tened en cuenta que estas propiedades pueden ser utilizadas en cada caso y que no se exige que sean exactamente como se representan en estos ejemplos.
- Ejemplo 1: "EEPJ con indicador del país sobre el que se genera" : Evento EEPJ en el que se indica el formato del código del país.
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
countryCodeFormat : 'ISO 3166-1',
countryCode : 'ESP',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
}
- Ejemplo 2: "EEPJ con indicador de la IP sobre el que se genera" : Evento EEPJ en el que se indica la IP desde la que se envío.
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
ip : '182.32.5.166',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
}
- Ejemplo 3: "EEPJ con indicador de la referencia GPS" : Evento EEPJ en el que se indica la posición desde la que se envío.
Para el ejemplo, uso las coordenadas GPS de la oficina de atSistemas BCN.
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
gpsCoordinates : {
latitude : '41.385878',
longitud : '2.170757'
},
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
}
1.4. Seguridad
La seguridad es otro punto importante y que casi nunca se tiene en cuenta. Solo cuando se tiene un problema serio entonces se empieza a tomar en serio o al final de los proyectos que no acordamos de que no hemos implementado nada... jejeje
Elementos que incluye:
- Consideraciones de Autenticación → Entidad (¿quién soy?) : personas, procesos o máquinas y su prueba de identidad (credenciales).
- Consideraciones de Autorización → Control de Acceso para impedir acceso a recursos privados (¿qué puedo hacer?) .
- Permite realizar una determina acción si un usuario tiene unos privilegios adecuados y suficientes.
- Control de acceso a redes y recursos
- Requerimientos de confidencialidad
- Capacidad de consumo total o parcial de la información -> No realizar enriquecimiento
- Requerimientos de codificación/encriptado
- La envoltura del evento no se suele encriptar
- El payload es el campo candidato a ser encriptado
- Requerimientos de Integridad → Evitar que sea modificada por un tercero
- Este punto esta muy relacionado con la inmutabilidad
- Se puede utilizar firma digital sobre el payload
- Aparecen problemas importantes en interrupciones, intercepciones, cambios de fuente origen o modificaciones a la hora de distribuir la información del evento
- Requerimientos de NO repudio → Ofrecer una prueba al emisor que la información fue entregada y una prueba al receptor del origen de la información recibida
- Prueba de origen
- Prueba de destino
- Consideraciones de Políticas / Backup de la información
- Consideraciones de Políticas de fuga de datos
- ...
Ejemplos de uso
Nota : Todos los ejemplos de uso irán centrados en considerar el envío de un email con payload en formato JSON (de aquí en adelante EEPJ (Envío Email Payload JSON)) de esta forma podréis ver las diferencias "particulares" de cada caso. Tener dn cuenta que estas propiedades pueden ser utilizadas en cada caso y que no se exige que sean exactamente como se representan en estos ejemplos.
- Ejemplo 1: "EEPJ con indicador de la IP autenticación" : Evento EEPJ en el que se indica la IP por lo que la funcionalidad debería de decidir si permite o no el envío de emails desde esa IP, considerando la IP como elemento destino o si permite su ejecución si la considera como la fuente de su creación
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
ip : '182.32.5.166',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
}
- Ejemplo 2: "EEPJ con indicador del usuario para la autenticación" : Evento EEPJ en el que se indica el usuario que en este caso lo normal es que sea el id del sistema que lo género
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
user : 'app_general',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
}
- Ejemplo 3: "EEPJ con token de seguridad" : Evento EEPJ en el que se indica token de seguridad
Nota : se puede utilizar un "Bearer" Token , JSON Web Token, etc.
{
eventId : 18,
eventName : 'SEND_EMAIL',
type : 'CREATE',
subtype : 'NEW',
object : 'USER',
eventDataFormat : 'JSON',
bearer : 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ',
payload : '{
to : 'destino@acme.com',
from : 'origen@acme.com',
subject : 'Importante',
content : 'Contenido Test'
}',
creationDate : '2020-12-30 23:15:58.999',
updateDate : '2020-12-30 23:20:25.153'
}
1.5. Modos de ejecución
Existen diferentes modos de ejecutar, o de que se provoque un evento, y con cada uno de ellos se cubren unas situaciones muy diferentes.
- Síncrono / Asíncrono
Síncrono / Asíncrono
- Síncrono: Requiere contestación por parte del consumidor. Dicha contestación puede ser una respuesta completa o bien meramente informativo sobre lo enviado (por ejemplo : "Tu petición esta siendo atendida").
- Asíncrono: No requiere contestación por parte del consumidor "Fire & Forget".
Origen
- Ad-Hoc: No depende de ningún otro u otros eventos para crearse.
- Disparador o Trigger: Un evento genera o es generado por otro/os al ejecutarse.
Aislado / Perteneciente
- Aislado: Evento que se crea sin buscar ningún tipo de relación con otros eventos.
- Perteneciente: Evento que puede ejecutarse dentro de un flujo de negocio o dentro de una ejecución compleja (para estados).
Importante: Un flujo se comporta como una máquina de estados para los eventos por lo que puede generar bifurcaciones en la generación de estados, paralelización, secuencialidad, respuesta en base a condiciones lógicas o temporales, etc.. Para ello, se puede permitir la transferencia de ese evento dentro de ese viaje o bien se pueden generar otros eventos.
Individual / Stream
Un Stream de eventos se considera cuando se recibe un flujo continuo y ordenado de eventos.
Un evento individual ya nos podemos imaginar lo que es :-).
Correlación
Un evento es correlacionado cuando se puede generar a partir de uno o varios elementos (otros elementos y/o condiciones).
Importante: Suele ser un punto que si no se define bien suele traer más de un quebradero de cabeza.
Hay que recordar los atributos para indicar su parentId, etc.
Inferencia
Un evento tiene una determinada inferencia en base al hecho de que su creación pueda deberse a una acción, otro evento e incluso el hecho de que no se produzca ninguna de las anteriores posibilidades.
Por ejemplo recibir o no un evento puede generar otro evento distinto para ese caso concreto, con esto ya te vas haciendo una idea sobre lo que me refiero.
Su creación se debe a:
- La falta de una validación podría generar un evento (por ejemplo : el hecho de que no existan eventos en una cola)
- La aparición de un determinado evento de otro tipo
- ...
Orquestación o coreografía
- Orquestación : Cuando la creación de un evento se debe a la existencia de algún tipo de componente SW que actúa como coordinador central. Esta pieza SW se dedica a "dar las órdenes" de lo que va a pasar en base a un plan establecido o al ver lo que esta ocurriendo en ese momento. Este componente SW generaría el o lo eventos necesarios según el análisis anterior. Se suele considerar un enfoque síncrono (aunque también puede será síncrono)
- Coreografía : Cuando la creación de un evento se debe a que este entienda lo que esta pasando y tome una decisión. En este caso NO existe un componente coordinador central y aunque existe un plan cada evento es responsable de dar y recibir órdenes. Se suele considerar un enfoque asíncrono
Reconciliación
Suele tener que ver más con la información pero estaría relacionado con las acciones a realizar sobre los eventos ante situaciones como: pérdidas, duplicados, etc.
Casos típicos:
- Ante perdidas se podrían generar los eventos que faltan por batching si la funcionalidad lo permitiera.
- Se puede asumir que hay pérdidas , por lo que se omitirían.
- Se pueden generar acciones de batching para establecer correcciones coherencia, integridad, etc.
- ...
Recuperación
Suele tener que ver con que los eventos puedan tener backups, genere información temporal, etc.
Con ello se facilita la respuesta rápida ante fallos, capacidad de recuperación total, mecanismos de auditoria parcial, etc.
Para mi, estos serían los aspectos más importantes a tener en cuenta sobre todo cuando se esta definiendo un arquitectura Event-Driven.
2. Conclusiones
¡Madre mía me ha vuelto a quedar un articulo "largo"! … veo que se me ha ido de las manos otra vez. Que sepáis que una amiga y compañera me ha dicho que estoy a un paso de competir con autores como Ken Follett (autor de la serie de libros de "Los pilares de la Tierra") o J.K. Rowling (autora de la serie de libros de "Harry Potter")...jejeje, lo único que pido es que no hagan una película de esto … L(° O °L)
Bueno... con este artículo he tratado de "cerrar el círculo", el objetivo era completar las otras problemáticas que faltaban y enseñar alguna forma de resolverlas ( o por lo menos ayudar a enfocarlas).
Resumen de las problemáticas planteadas entre los 2 artículos :
- Organizativas
- Internacionalización
- Ordenación
- Inmutabilidad
- Expiración
- Ubicación
- Seguridad
- Modos de Ejecución
En concreto, en este artículo se han abordado los temas en negrita, si los juntamos con los del anterior artículo podemos tener una base para empezar a diseñar nuestros casos de uso complejos desde 0. Seguramente me haya olvidado algún caso o enfoque, pero creo que las cosas más típicas están cubiertas. Así, no nos conformaremos con tener un evento "Hola Mundo" en producción, ese caso siempre funciona y nunca es el que nos piden...jejeje
Os voy avisando... ¡Prepararos para lo que vendrá después! Y si te ha gustado, ¡síguenos en Twitter!