FastFoodCity es un sistema distribuido diseñado para gestionar pedidos mediante una arquitectura basada en microservicios. El sistema separa responsabilidades entre servicios independientes, utiliza persistencia aislada por servicio y combina comunicación síncrona con eventos asincrónicos para mantener consistencia eventual entre los distintos componentes.
El proyecto demuestra patrones comunes en sistemas distribuidos modernos como separación entre modelos de escritura y lectura, mensajería basada en eventos, proyección de modelos optimizados para consulta y observabilidad mediante logging estructurado.
| Tecnología | Uso |
|---|---|
| .NET 8 | Plataforma principal |
| Minimal APIs | Implementación de APIs |
| EF Core | Persistencia |
| PostgreSQL | Base de datos transaccional |
| MongoDB | Modelos de lectura |
| RabbitMQ | Mensajería |
| Redis | Cache |
| Serilog | Logging estructurado |
| Seq | Agregación de logs |
| Docker | Infraestructura |
El sistema está compuesto por múltiples servicios independientes que colaboran mediante llamadas HTTP y eventos asincrónicos.
┌───────────────┐
│ API Gateway │
└───────┬───────┘
│
│ HTTP
│
┌───────▼────────┐
│ OrderingService │
└───────┬────────┘
│
│ HTTP
│
┌───────▼────────┐
│ PaymentService │
└───────┬────────┘
│
│ Evento
│
┌───────▼────────┐
│ RabbitMQ │
└───────┬────────┘
│
│
┌───────▼────────┐
│ ProjectionSvc │
└───────┬────────┘
│
│
MongoDB
| Servicio | Responsabilidad |
|---|---|
| API Gateway | Punto de entrada al sistema |
| OrderingService | Gestión de carritos y pedidos |
| PaymentService | Cálculo del total del pedido |
| ProjectionService | Construcción de modelos de lectura |
El Ordering Service gestiona el flujo principal del sistema relacionado con la creación y administración de pedidos.
Responsabilidades principales:
- creación de carritos
- modificación de carritos
- checkout del carrito
- creación de pedidos
- coordinación con el servicio de pagos
Persistencia utilizada:
PostgreSQL
Este servicio implementa el patrón Outbox para garantizar consistencia entre las operaciones de base de datos y la publicación de eventos.
El Payment Service incluido en este proyecto funciona actualmente como un sandbox simplificado cuyo objetivo es demostrar la integración entre servicios durante el proceso de checkout.
Actualmente el servicio:
- recibe el subtotal del pedido
- calcula impuestos o costos adicionales
- devuelve el total final al Ordering Service
- registra la transacción en su base de datos
Persistencia utilizada:
PostgreSQL
Este servicio es invocado de forma síncrona por el Ordering Service durante el proceso de checkout.
En una versión futura se planea desarrollar un sistema de pagos completo como un proyecto independiente, con características propias de una plataforma de pagos real.
Este nuevo servicio incluiría funcionalidades como:
- procesamiento de pagos asincrónico
- reintentos automáticos ante fallos
- múltiples métodos de pago
- manejo de estados de pago
- reconciliación de pagos
- manejo de timeouts y compensaciones
Esto permitiría desacoplar completamente la lógica de pagos del flujo principal del sistema de pedidos.
El Projection Service es responsable de construir los modelos de lectura del sistema.
Este servicio escucha eventos provenientes de RabbitMQ y actualiza las proyecciones almacenadas en MongoDB.
Responsabilidades principales:
- consumir eventos publicados por otros servicios
- transformar eventos en modelos optimizados para consulta
- persistir dichos modelos en MongoDB
Persistencia utilizada:
MongoDB
Actualmente el sistema publica el evento:
OrderCreatedEvent
Este evento representa la creación de un pedido dentro del sistema y es consumido por el Projection Service para construir los modelos de lectura.
Flujo de consumo del evento:
- RabbitMQ recibe el evento
- ProjectionService consume el evento
- Se construye un
OrderReadModel - El modelo se almacena en MongoDB
Este enfoque permite que las consultas se realicen sobre modelos optimizados sin afectar las bases de datos transaccionales.
El proceso completo de creación de un pedido ocurre de la siguiente manera:
Cliente
│
▼
API Gateway
│
▼
Ordering Service
│
│ crea Order
│
▼
Payment Service
│
│ calcula total
│
▼
Ordering confirma pedido
│
▼
Evento OrderCreated
│
▼
RabbitMQ
│
▼
Projection Service
│
▼
MongoDB (read model)
- El cliente inicia el checkout del carrito
- Ordering valida el carrito
- Ordering crea el pedido
- Ordering solicita el cálculo del total al Payment Service
- Payment calcula impuestos y costos adicionales
- Ordering confirma el pedido
- Se registra el evento OrderCreated
- El evento se publica en RabbitMQ
- Projection Service consume el evento
- Se genera el modelo de lectura en MongoDB
El siguiente diagrama representa la interacción completa entre servicios durante el proceso de checkout.
Cliente Gateway Ordering Payment RabbitMQ Projection MongoDB
│ │ │ │ │ │ │
│ POST checkout │ │ │ │ │ │
│──────────────▶│ │ │ │ │ │
│ │ Forward │ │ │ │ │
│ │─────────────▶│ │ │ │ │
│ │ │ Create Order │ │ │ │
│ │ │─────────────▶│ │ │ │
│ │ │ Request total│ │ │ │
│ │ │─────────────▶│ │ │ │
│ │ │ │ Calculate │ │ │
│ │ │ │ taxes/shipping│ │ │
│ │ │ │──────────────▶│ │ │
│ │ │ Receive total│ │ │ │
│ │ │◀─────────────│ │ │ │
│ │ │ Confirm Order│ │ │ │
│ │ │─────────────▶│ │ │ │
│ │ │ Publish Event│ │ │ │
│ │ │─────────────▶│ │ │ │
│ │ │ │ │ OrderCreated │ │
│ │ │ │ │──────────────▶│ │
│ │ │ │ │ │ Build ReadModel│
│ │ │ │ │ │──────────────▶│
│ │ │ │ │ │ Stored │
Este flujo permite mantener separadas las responsabilidades de cada servicio y facilita la escalabilidad del sistema.
| Método | Endpoint | Descripción |
|---|---|---|
| POST | /api/v1/carts | Crear un nuevo carrito |
| POST | /api/v1/carts/{id}/items | Agregar producto al carrito |
| DELETE | /api/v1/carts/{id}/items/{productId} | Eliminar producto del carrito |
| GET | /api/v1/carts/{id} | Obtener carrito |
| POST | /api/v1/carts/{id}/checkout | Finalizar compra |
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/v1/orders/{id} | Obtener pedido |
| Método | Endpoint | Descripción |
|---|---|---|
| POST | /api/v1/payments | Procesar pago |
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/v1/health | Estado del servicio |
| POST | /api/v1/test-insert | Endpoint de prueba para inserción en Mongo |
El sistema utiliza logging estructurado mediante Serilog.
Todos los servicios envían logs a Seq, lo que permite:
- trazabilidad entre servicios
- análisis centralizado de errores
- monitoreo del sistema distribuido
Las siguientes mejoras están contempladas para futuras versiones del sistema.
Uso avanzado de Redis para:
- cache de catálogo
- cache de carritos activos
- limitación distribuida de solicitudes
- circuit breakers
- políticas de reintento
- manejo de dead letter queues
- métricas del sistema
- trazabilidad distribuida
- monitoreo avanzado
Se planea incorporar pruebas unitarias automatizadas para los servicios principales con el objetivo de integrarlas en pipelines de CI/CD, permitiendo validación automática del sistema durante el proceso de integración y despliegue.