Microservicio del ecosistema MANI (TRAMA · Ingeniería de Software), desarrollado en C# y .NET 8 (ASP.NET Core Web API), responsable del algoritmo de emparejamiento geográfico y la exclusión concurrente de asignación.
Este repositorio gestiona el ciclo operativo de despacho: cálculo de cercanía entre manicuristas y clientes, evaluación de candidatos y resolución atómica de colisiones de aceptación (Race Conditions).
Dentro de la arquitectura de servicios de MANI, MANI-.NET opera como el motor de alta concurrencia y despacho:
- Puerto Interno:
5000 - Exposición Externa: Vía
MANI-APIGatewaybajo el prefijo/api/v1/dispatch/*. - Capacidades de Negocio (SRS V3 / RNF-05):
- RF-12: Emparejamiento de manicuristas según cercanía geográfica y disponibilidad.
- RF-14: Ciclo de aceptación y rechazo de órdenes de servicio por parte de profesionales.
- RNF-03: Idempotencia en comandos de despacho.
- RNF-05: Exclusión Concurrente Atómica: Si múltiples manicuristas intentan aceptar una misma orden simultáneamente, la primera confirmada gana (
200 OK) y las solicitudes colisionantes reciben inmediatamente un código HTTP409 Conflict.
flowchart LR
GW["MANI-APIGateway (Puerto :80)"] -->|/api/v1/dispatch/*| DotNet["MANI-.NET (:5000)"]
Node["MANI-Node"] -.->|Coordinar Despacho| DotNet
DotNet -.->|Consultar Prioridad| Java["MANI-Java (:8080)"]
| Método | Ruta en Gateway | Descripción | Código Éxito | Código Conflicto |
|---|---|---|---|---|
GET |
/api/v1/dispatch/health |
Healthcheck y estado del servicio de despacho. | 200 OK |
N/A |
POST |
/api/v1/dispatch/match |
Algoritmo de búsqueda de profesionales por cercanía. | 200 OK |
400 |
POST |
/api/v1/dispatch/requests/{id}/accept |
Aceptación atómica de servicio con exclusión mutua. | 200 OK |
409 Conflict |
Petición (POST /api/v1/dispatch/requests/req-101/accept):
{
"allyId": "aliado-carolina"
}- Respuesta del primer aliado que acepta (
200 OK):
{
"message": "Solicitud asignada exitosamente al profesional.",
"requestId": "req-101",
"assignedAllyId": "aliado-carolina",
"status": "ASSIGNED",
"correlationId": "c9a4b2a8-1234-5678-90ab-cdef12345678",
"timestamp": "2026-10-05T19:50:00Z"
}- Respuesta a cualquier intento posterior (
409 Conflict):
{
"error": "La solicitud ya fue aceptada por otro profesional.",
"status": 409,
"assignedTo": "aliado-carolina",
"correlationId": "c9a4b2a8-1234-5678-90ab-cdef12345678",
"timestamp": "2026-10-05T19:50:01Z"
}- Framework: .NET 8 (ASP.NET Core Web API).
- Lenguaje: C# 12.
- Servidor Kestrel: Configurado para escuchar en puerto
5000. - Contenerización: Docker multi-stage (
dotnet/sdk:8.0+dotnet/aspnet:8.0).
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ServiceUrls": {
"CoreService": "http://core-service:3000",
"RulesService": "http://rules-service:8080",
"Gateway": "http://localhost:80"
}
}# Restaurar dependencias
dotnet restore
# Ejecutar aplicación en puerto 5000
dotnet run# Construir imagen Docker
docker build -t mani-dispatch-dotnet:local .
# Ejecutar contenedor
docker run -d -p 5000:5000 --name mani-dispatch mani-dispatch-dotnet:localLas pruebas están en tests/Mani.Dispatch.Tests (xUnit 2 + coverlet, .NET 8).
# Ejecutar pruebas
dotnet test tests/Mani.Dispatch.Tests
# Ejecutar pruebas y generar el reporte de cobertura (OpenCover) en ./TestResults
dotnet test tests/Mani.Dispatch.Tests --collect:"XPlat Code Coverage" --results-directory ./TestResults -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencoverEl workflow CI (.github/workflows/ci.yml) ejecuta lo mismo en cada Pull Request y en cada push a main, y publica el reporte como artefacto. Para conectarlo al Quality Gate, el análisis de SonarQube debe leer **/coverage.opencover.xml (sonar.cs.opencover.reportsPaths); crear el proyecto en SonarCloud y su token queda pendiente de DevOps.
- Organización: TRAMA · Ingeniería de Software
- Repositorio Oficial: MANI-.NET
Dispatch no lee las tablas de Core (SAD §7.4, ADR-0030): pide la elegibilidad de aliados y el contexto de la solicitud por HTTP.
| Variable | Uso |
|---|---|
CORE_SERVICE_URL |
URL base de Core. Obligatoria; sin ella (o si Core no responde, con tiempo de espera de 3 s) los endpoints de elegibilidad devuelven 503. |
Endpoints que Dispatch consume en Core: GET /api/v1/allies/me (perfil del aliado autenticado), GET /api/v1/allies/eligible (admite tipo=PERSONA_NATURAL|PERSONA_JURIDICA|EMPLEADO_DIRECTO) y GET /api/v1/solicitudes/{id}/context. Dispatch reenvía el Authorization (JWT del usuario) y X-Correlation-ID; Core autentica con su middleware y toma tenant y rol del claim verificado (ADR-0030). X-Tenant-Id viaja solo como referencia.