En esta última clase aplicaremos todo lo aprendido para construir un sistema distribuido completo con Orleans. Implementaremos un sistema de gestión de pedidos en línea, asegurando escalabilidad, persistencia y seguridad.
Objetivos de la Clase
- Construir una arquitectura distribuida basada en Orleans.
- Implementar Granos para gestionar usuarios, pedidos y pagos.
- Utilizar persistencia con SQL Server para almacenar el estado.
- Exponer Orleans como API REST con ASP.NET Core.
- Asegurar alta disponibilidad y escalabilidad con Orleans.
Arquitectura del Sistema
Componentes principales
Usuarios → Registran y consultan información sobre sus cuentas.
Pedidos → Un usuario puede hacer múltiples pedidos.
Pagos → Cada pedido requiere un pago procesado.
Diagrama del Flujo del Sistema
- Un usuario crea un pedido.
- El sistema asigna un número de pedido único.
- Se procesa el pago de forma asincrónica.
- Cuando el pago se confirma, el pedido cambia a estado «completado».
- El usuario puede consultar el historial de pedidos en cualquier momento.
Implementar los Granos del Sistema
Interfaz del Grano de Usuario
using System.Threading.Tasks;
using Orleans;
public interface IUsuarioGrain : IGrainWithStringKey
{
Task RegistrarUsuario(string nombre, string email);
Task<string> ObtenerInformacion();
}
Implementación del Grano de Usuario
using System.Threading.Tasks;
using Orleans;
public class UsuarioGrain : Grain, IUsuarioGrain
{
private string _nombre;
private string _email;
public Task RegistrarUsuario(string nombre, string email)
{
_nombre = nombre;
_email = email;
return Task.CompletedTask;
}
public Task<string> ObtenerInformacion()
{
return Task.FromResult($"Usuario: {_nombre}, Email: {_email}");
}
}
Este Grano almacena información básica del usuario.
Interfaz del Grano de Pedido
using System.Threading.Tasks;
using Orleans;
public interface IPedidoGrain : IGrainWithGuidKey
{
Task CrearPedido(string usuarioId, decimal monto);
Task ConfirmarPago();
Task<string> ObtenerEstado();
}
Implementación del Grano de Pedido
using System.Threading.Tasks;
using Orleans;
public class PedidoGrain : Grain, IPedidoGrain
{
private string _usuarioId;
private decimal _monto;
private bool _pagado = false;
public Task CrearPedido(string usuarioId, decimal monto)
{
_usuarioId = usuarioId;
_monto = monto;
return Task.CompletedTask;
}
public Task ConfirmarPago()
{
_pagado = true;
return Task.CompletedTask;
}
public Task<string> ObtenerEstado()
{
return Task.FromResult(_pagado ? "Completado" : "Pendiente de pago");
}
}
Este Grano representa un pedido y su estado de pago.
Interfaz del Grano de Pagos
using System.Threading.Tasks;
using Orleans;
public interface IPagoGrain : IGrainWithGuidKey
{
Task<bool> ProcesarPago(string pedidoId, decimal monto);
}
Implementación del Grano de Pagos
using System;
using System.Threading.Tasks;
using Orleans;
public class PagoGrain : Grain, IPagoGrain
{
public async Task<bool> ProcesarPago(string pedidoId, decimal monto)
{
await Task.Delay(2000); // Simular procesamiento de pago
Console.WriteLine($"Pago de {monto:C} procesado para el pedido {pedidoId}");
return true;
}
}
Este Grano simula el procesamiento de un pago.
Configurar Persistencia en SQL Server
Agregar Configuración en Program.cs
siloBuilder.AddAdoNetGrainStorage("pedidoStore", options =>
{
options.Invariant = "System.Data.SqlClient";
options.ConnectionString = "Server=localhost;Database=OrleansPedidos;User Id=sa;Password=YourPassword;";
});
Esto permite que los pedidos persistan en la base de datos.
Exponer Orleans como API REST
Crear PedidoController.cs
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Orleans;
[ApiController]
[Route("api/pedidos")]
public class PedidoController : ControllerBase
{
private readonly IGrainFactory _grainFactory;
public PedidoController(IGrainFactory grainFactory)
{
_grainFactory = grainFactory;
}
[HttpPost("{usuarioId}/crear")]
public async Task<IActionResult> CrearPedido(string usuarioId, [FromBody] decimal monto)
{
var pedidoGrain = _grainFactory.GetGrain<IPedidoGrain>(Guid.NewGuid());
await pedidoGrain.CrearPedido(usuarioId, monto);
return Ok($"Pedido creado con éxito para usuario {usuarioId}");
}
[HttpPost("{pedidoId}/pagar")]
public async Task<IActionResult> PagarPedido(Guid pedidoId)
{
var pagoGrain = _grainFactory.GetGrain<IPagoGrain>(pedidoId);
bool pagoExitoso = await pagoGrain.ProcesarPago(pedidoId.ToString(), 100);
if (pagoExitoso)
{
var pedidoGrain = _grainFactory.GetGrain<IPedidoGrain>(pedidoId);
await pedidoGrain.ConfirmarPago();
return Ok("Pago procesado con éxito.");
}
return BadRequest("Error en el pago.");
}
[HttpGet("{pedidoId}/estado")]
public async Task<IActionResult> ObtenerEstado(Guid pedidoId)
{
var pedidoGrain = _grainFactory.GetGrain<IPedidoGrain>(pedidoId);
string estado = await pedidoGrain.ObtenerEstado();
return Ok($"Estado del pedido: {estado}");
}
}
Esto permite interactuar con Orleans usando HTTP.
Probar la Aplicación
Ejecutar Orleans y la API
dotnet run
Crear un Pedido
curl -X POST "http://localhost:5000/api/pedidos/user123/crear" -H "Content-Type: application/json" -d "100"
Salida esperada:
Pedido creado con éxito para usuario user123
Pagar un Pedido
curl -X POST "http://localhost:5000/api/pedidos/{pedidoId}/pagar"
Salida esperada:
Pago procesado con éxito.
Consultar Estado del Pedido
curl -X GET "http://localhost:5000/api/pedidos/{pedidoId}/estado"
Salida esperada:
Estado del pedido: Completado
Cuestionario de Autoevaluación
- ¿Cómo se estructuró el sistema de gestión de pedidos en Orleans?
- ¿Cómo Orleans maneja la persistencia de pedidos en SQL Server?
- ¿Cómo interactúan los Granos de Pedidos y Pagos en la API REST?
- ¿Qué ventajas ofrece Orleans en comparación con un sistema tradicional basado en bases de datos centralizadas?
- ¿Cómo Orleans asegura escalabilidad y concurrencia en este sistema?
Resumen de la Clase
- Construimos un sistema distribuido completo con Orleans.
- Usamos Granos para Usuarios, Pedidos y Pagos.
- Persistimos datos en SQL Server para garantizar durabilidad.
- Exponemos Orleans como API REST con ASP.NET Core.
Conclusiones y Agradecimientos
Después de recorrer 20 clases, hemos explorado todos los aspectos esenciales de Microsoft Orleans, desde los fundamentos hasta su aplicación en sistemas distribuidos escalables y de alta disponibilidad. Orleans nos ha demostrado ser una tecnología poderosa y flexible para construir aplicaciones distribuidas, optimizando la gestión de concurrencia, persistencia y escalabilidad de una manera sencilla y eficiente.
¿Qué hemos aprendido?
Conceptos Fundamentales de Orleans
- Cómo Orleans implementa el Actor Model para gestionar concurrencia y estado de manera eficiente.
- Activación y ciclo de vida de los Granos en un sistema distribuido.
Orleans en Producción
- Persistencia de Granos en bases de datos SQL Server y MongoDB.
- Orleans Streams para comunicación eficiente entre Granos.
- Seguridad con autenticación JWT y autorización en Orleans.
Optimización y Escalabilidad
- Mejoramos la performance ajustando activación de Granos, uso de Streams y balanceo de carga.
- Alta disponibilidad con múltiples nodos Orleans, asegurando redundancia y resiliencia.
- Uso de Kubernetes y Docker para entornos de producción escalables.
Caso Práctico Completo
- Implementamos un sistema distribuido real usando Orleans con API REST en ASP.NET Core.
- Aplicamos persistencia, autenticación, transacciones y escalabilidad en un entorno Orleans de producción.
Agradecimientos Especiales
¡Gracias por seguir este curso y sumergirte en el mundo de Orleans!
Este no es el final, sino el comienzo de tu viaje en sistemas distribuidos. Con Orleans, ahora tienes el conocimiento y las herramientas para desarrollar aplicaciones altamente escalables y resilientes.