Hay muchas soluciones que comprometen más de lo que me siento cómodo. Por supuesto, si su caso de uso es complejo, como mover dinero entre diferentes bancos, las alternativas más agradables pueden ser imposibles. Pero echemos un vistazo a lo que podemos hacer en el escenario común, donde el uso de microservicios interfiere con nuestras posibles transacciones de base de datos.
Opción 1: evite la necesidad de transacciones si es posible
Obvio y mencionado anteriormente, pero ideal si podemos manejarlo. ¿Pertenecían realmente los componentes al mismo microservicio? ¿O podemos rediseñar el (los) sistema (s) para que la transacción se vuelva innecesaria? Quizás aceptar el no sacrificio es el sacrificio más asequible.
Opción 2: usar una cola
Si hay suficiente certeza de que el otro servicio tendrá éxito en lo que queramos que haga, podemos llamarlo a través de alguna forma de cola. El elemento en cola no se recogerá hasta más tarde, pero podemos asegurarnos de que el elemento esté en cola .
Por ejemplo, digamos que queremos insertar una entidad y enviar un correo electrónico, como una sola transacción. En lugar de llamar al servidor de correo, colocamos el correo en una tabla.
Begin transaction
Insert entity
Insert e-mail
Commit transaction
Un claro inconveniente es que varios microservicios necesitarán acceso a la misma tabla.
Opción 3: haga el trabajo externo en último lugar, justo antes de completar la transacción
Este enfoque se basa en el supuesto de que es muy poco probable que la transacción se cometa.
Begin transaction
Insert entity
Insert another entity
Make external call
Commit transaction
Si las consultas fallan, la llamada externa aún no se ha realizado. Si la llamada externa falla, la transacción nunca se confirma.
Este enfoque viene con las limitaciones de que solo podemos hacer una llamada externa, y debe hacerse en último lugar (es decir, no podemos usar su resultado en nuestras consultas).
Opción 4: crear cosas en un estado pendiente
Como se publicó aquí , podemos hacer que varios microservicios creen diferentes componentes, cada uno en un estado pendiente, sin transacciones.
Se realiza cualquier validación, pero nada se crea en un estado definitivo. Después de que todo ha sido creado exitosamente, cada componente es activado. Por lo general, esta operación es tan simple y las probabilidades de que algo salga mal son tan pequeñas, que incluso podemos preferir realizar la activación sin transacciones.
El mayor inconveniente es probablemente que tenemos que tener en cuenta la existencia de elementos pendientes. Cualquier consulta de selección debe considerar si se deben incluir los datos pendientes. La mayoría debería ignorarlo. Y las actualizaciones son otra historia en conjunto.
Opción 5: permitir que el microservicio comparta su consulta
¿Ninguna de las otras opciones lo hace por ti? Entonces pongámonos heterodoxos .
Dependiendo de la compañía, esta puede ser inaceptable. Soy consciente. Esto es poco ortodoxo. Si no es aceptable, sigue otra ruta. Pero si esto se ajusta a su situación, resuelve el problema de manera simple y poderosa. Podría ser el compromiso más aceptable.
Hay una forma de convertir las consultas de múltiples microservicios en una transacción simple y única de base de datos.
Devuelva la consulta, en lugar de ejecutarla.
Begin transaction
Execute our own query
Make external call, receiving a query
Execute received query
Commit transaction
En cuanto a la red, cada microservicio debe poder acceder a cada base de datos. Tenga esto en cuenta, también con respecto a la escala futura.
Si las bases de datos involucradas en la transacción están en el mismo servidor, esta será una transacción regular. Si están en servidores diferentes, será una transacción distribuida. El código es el mismo independientemente.
Recibimos la consulta, incluido su tipo de conexión, sus parámetros y su cadena de conexión. Podemos envolverlo en una ordenada clase de comando ejecutable, manteniendo el flujo legible: el llamado al microservicio resulta en un comando, que ejecutamos, como parte de nuestra transacción.
La cadena de conexión es lo que nos brinda el microservicio de origen, por lo que para todos los propósitos y propósitos, la consulta aún se considera ejecutada por ese microservicio. Solo lo estamos enrutando físicamente a través del microservicio del cliente. Eso hace una diferencia? Bueno, nos permite ponerlo en la misma transacción con otra consulta.
Si el compromiso es aceptable, este enfoque nos da la transaccionalidad simple de una aplicación de monolito, en una arquitectura de microservicio.