En nuestro complejo mundo de los microservicios de software, la idempotencia emerge como un pilar fundamental. Este concepto, aunque suene técnico, encierra un principio simple pero poderoso que ayuda muy efectivamente a prevenir procesamientos duplicados en nuestras aplicaciones.
En Pomelo, la idempotencia se convierte en un elemento crucial para garantizar la consistencia, fiabilidad y seguridad en el procesamiento de solicitudes, ¡más aún si se aplica a un mundo tan crítico como la emisión de tarjetas y el procesamiento de transacciones financieras! En este artículo, exploraremos a fondo este concepto, cómo lo aplicamos en nuestros microservicios y por qué es tan vital para que funcionen de forma eficiente y confiable.
¿Que es la idempotencia?
En matemáticas, una función es idempotente si, aplicándola múltiples veces, obtienes el mismo resultado que aplicándola una única vez. Por ejemplo, para la operación aritmética del producto, el número 1 es idempotente. No importa cuantas veces multipliques por 1 a cualquier número real, siempre obtendrás el mismo resultado: el número original que estás multiplicando.
Vamos a ver un problema de idempotencia un poco más real: imagina que un comensal de un restaurante pide el mismo plato dos veces pensando que el camarero no lo escuchó. Si el camarero no aplicara el concepto de idempotencia, le serviría dos veces el mismo plato.
Idempotencia aplicada al mundo del software
En software tenemos el mismo problema que el camarero que mencionamos arriba. En pocas palabras, una operación es idempotente si al aplicarla una vez o múltiples veces produce el mismo resultado. Según el RFC de HTTP, un método de solicitud se considera idempotente si “el efecto previsto en el servidor causado por múltiples solicitudes idénticas con ese método, es igual al efecto para una única solicitud de ese tipo”.
Idempotencia en Pomelo
La idempotencia parece un concepto relevante, pero a veces no se le da la importancia que merece – y podría llevar a errores críticos en nuestras aplicaciones.
Veamos un ejemplo:
En este ejemplo, podemos ver como un cliente intenta crear una tarjeta en nuestra solución de Cards. En la primera solicitud, el cliente deja de esperar la respuesta de Cards API y arroja un timeout. Sin embargo, la aplicación sigue procesando el pedido y le devuelve la respuesta al cliente creando la tarjeta.
La segunda vez que el cliente intentó ejecutar el pedido, todo funcionó a la perfección y la tarjeta fue creada, devolviéndole una respuesta exitosa. El problema en este escenario es que el cliente quiso crear una sola tarjeta y la API creó dos, yendo en contra de la idempotencia.
¿Cómo resolvemos este problema en Pomelo?
Para poder resolver este problema, hacemos uso de un header llamado x-idempotency-key. Por lo tanto, cuando nuestro cliente hace requests, envía un ID único por cada uno, para que el servidor pueda entender que dos requests son exactamente iguales. En caso de que alguno falle y amerite un reintento (5xx, Timeout) este volvería a ser intentado con el mismo header y el mismo valor.
Del lado del servidor, cada vez que se ejecuta un request con header de idempotencia, verificamos en una base de datos de muy rápido acceso si ya se intentó hacer un request con el x-idempotency-key.
- Si el requisito no existe en nuestra base de datos para ese ID, se lo procesa normalmente y luego se almacena el x-idempotency-key junto con la response.
Si el request ya existe en nuestra base de datos para ese ID, se buscará la respuesta almacenada y se devolverá al cliente sin volver a ejecutarse.
En este último gráfico podemos ver que por más que el servidor haya recibido 2 requests para crear una tarjeta, al haberla enviado con el mismo header de idempotencia, es interpretado como un solo request. Y, la segunda vez, devolverá el response sin ejecutar nuevamente la creación de la tarjetas.
Conclusión
La idempotencia se revela como un principio esencial en el mundo de los microservicios, particularmente en el dominio tan crítico de Pomelo, donde emitimos tarjetas y procesamos transacciones financieras. De todas maneras, solo logrará ser efectivo con la ayuda e implementación del lado del cliente para evitar problemas cruciales como la creación duplicada de recursos.
En Pomelo, adoptamos un enfoque proactivo mediante el uso del header x-idempotency-key, asegurando respuestas coherentes y eficientes. Así, además se demuestra que la idempotencia no solo es un concepto técnico, sino una parte vital para la integridad y confiabilidad de nuestras aplicaciones.