LilHermes 2.1.0
dotnet add package LilHermes --version 2.1.0
NuGet\Install-Package LilHermes -Version 2.1.0
<PackageReference Include="LilHermes" Version="2.1.0" />
<PackageVersion Include="LilHermes" Version="2.1.0" />
<PackageReference Include="LilHermes" />
paket add LilHermes --version 2.1.0
#r "nuget: LilHermes, 2.1.0"
#:package LilHermes@2.1.0
#addin nuget:?package=LilHermes&version=2.1.0
#tool nuget:?package=LilHermes&version=2.1.0
LilHermes
Wrapper ligero de RabbitMQ para .NET Standard 2.0. Proporciona abstracciones de publicación y consumo de mensajes con soporte nativo de trazabilidad distribuida (OpenTelemetry) y Dead-Letter Queue (DLQ).
Contenido
- Requisitos
- Proyectos
- Instalación vía DI
- Configuración
- Publicar mensajes
- Consumir mensajes
- Dead-Letter Queue
- OpenTelemetry
- Comandos de desarrollo
- Tests
Requisitos
- .NET Standard 2.0 (aplicaciones .NET 6+, .NET Framework 4.6.1+)
- RabbitMQ corriendo y accesible
- (Opcional) Colector OTLP en
http://localhost:4318para trazas
Proyectos
| Paquete | Descripción |
|---|---|
LilHermes.Abstractions |
Contratos: MessageBusOptions, MessageContext<T>, enums |
LilHermes.Infrastructure |
Implementaciones: publisher, consumer, connection manager, telemetría |
Instalación vía DI
Registra los servicios en Program.cs o en tu Startup.cs:
// Publisher + Consumer (stack completo)
builder.Services.AddLilHermes(options =>
{
options.ConnectionOptions.HostName = "localhost";
options.ConnectionOptions.Username = "guest";
options.ConnectionOptions.Password = "guest";
options.PublishOptions.Exchange = "mi-exchange";
options.PublishOptions.ExchangeType = RabbitMQExchangeType.Direct;
options.ConsumerOptions.QueueName = "mi-cola";
options.ConsumerOptions.ExchangeName = "mi-exchange";
});
// Solo publisher
builder.Services.AddLilHermesPublisher(options => { ... });
// Solo consumer
builder.Services.AddLilHermesConsumer(options => { ... });
Configuración
Conexión (ConnectionOptions)
| Propiedad | Default | Descripción |
|---|---|---|
HostName |
127.0.0.1 |
Host del broker |
Port |
5672 |
Puerto AMQP |
Username / Password |
guest |
Credenciales |
VirtualHost |
/ |
VHost de RabbitMQ |
ConnectionUri |
— | URI completa (alternativa a host/port) |
EnabledCluster |
false |
Activa modo clúster |
Endpoints |
— | Lista de nodos del clúster |
AutomaticRecoveryEnabled |
true |
Reconexión automática |
NetworkRecoveryInterval |
5s |
Intervalo entre reintentos de reconexión |
Publicación (PublishOptions)
| Propiedad | Default | Descripción |
|---|---|---|
Exchange |
— | Nombre del exchange |
ExchangeType |
— | Direct, Topic, Fanout, Headers |
Persistent |
true |
Mensajes persistentes en disco |
PublisherConfirmationsEnabled |
true |
Confirmaciones del broker |
Priority |
Normal |
Low, Normal, High |
Consumo (ConsumerOptions)
| Propiedad | Default | Descripción |
|---|---|---|
QueueName |
LilHermes-Queue-v0 |
Nombre de la cola |
ExchangeName |
— | Exchange al que se vincula |
RoutingKeys |
— | Claves de enrutamiento |
AcknowledgeMode |
Manual |
Auto o Manual |
PrefetchCount |
100 |
Mensajes prefetcheados por consumer |
MaxRetryCount |
3 |
Reintentos antes de enviar a DLQ |
RetryDelayMs |
1000 |
Delay entre reintentos (ms) |
EnableDLQ |
false |
Habilita Dead-Letter Queue |
MessageTTL |
30000 |
TTL de mensajes en cola de retry (ms) |
Publicar mensajes
Inyecta IMessagePublisher y crea el mensaje con MessageContext.Create:
public class MiServicio(IMessagePublisher publisher)
{
public async Task EnviarPedidoAsync(Pedido pedido, CancellationToken ct)
{
// CorrelationId, MessageId y Timestamp (UTC) se generan automáticamente
var mensaje = MessageContext.Create(pedido, "servicio-pedidos");
await publisher.PublishAsync(mensaje, routingKey: "pedidos.nuevo", ct);
}
}
Si el mensaje ya tiene un id propio (por ejemplo, el id del documento), pásalo como tercer
argumento: MessageContext.Create(pedido, "servicio-pedidos", pedido.Id.ToString()).
Desde la 2.1.0, Timestamp se genera en UTC.
Publicación en lote
var mensajes = pedidos.Select(p => MessageContext.Create(p, "servicio-pedidos"));
await publisher.PublishBatchAsync(mensajes, routingKey: "pedidos.lote", ct);
Consumir mensajes
Modo simple (solo el payload)
public class MiConsumerService(IMessageConsumer consumer) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken ct)
{
await consumer.StartConsumingAsync<Pedido>(
async (pedido, deliveryTag) =>
{
// Procesar pedido
await ProcesarAsync(pedido);
await consumer.AckAsync(deliveryTag);
},
ct);
}
}
Modo con contexto (acceso a metadatos y trazas)
await consumer.StartConsumingWithContextAsync<Pedido>(
async (context, deliveryTag) =>
{
var correlationId = context.CorrelationId;
var pedido = context.Data;
await ProcesarAsync(pedido);
await consumer.AckAsync(deliveryTag);
},
ct);
Dead-Letter Queue
Cuando EnableDLQ = true, LilHermes crea automáticamente la siguiente infraestructura en RabbitMQ:
[Exchange principal] → [Cola principal]
↓ (fallo)
[Cola de retry] ← TTL → [Exchange principal]
↓ (MaxRetryCount agotado)
[Cola parqueada (errores)]
Activa DLQ en la configuración del consumer:
options.ConsumerOptions.EnableDLQ = true;
options.ConsumerOptions.MaxRetryCount = 3;
options.ConsumerOptions.RetryDelayMs = 2000;
options.ConsumerOptions.MessageTTL = 60000;
Los mensajes que superan MaxRetryCount quedan en la cola {QueueName}.error para inspección manual.
OpenTelemetry
LilHermes instrumenta automáticamente la publicación y el consumo con System.Diagnostics
(ActivitySource y Meter). No depende de los paquetes de OpenTelemetry: cada servicio usa
la versión de OpenTelemetry que necesite y registra LilHermes por nombre.
El nombre es el SourceName configurado en AddLilHermes (por defecto
LilHermesTelemetry.DefaultSourceName, es decir "LilHermes"). Trazas y métricas usan el
mismo nombre.
Registrar trazas y métricas
builder.Services.AddLilHermes(options =>
{
options.SourceName = "MiServicio";
// ...
});
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("MiServicio") // <-- trazas de LilHermes
.AddOtlpExporter())
.WithMetrics(metrics => metrics
.AddMeter("MiServicio") // <-- métricas de LilHermes
.AddOtlpExporter());
Migración de 1.x a 2.0
En la 2.0 se eliminó AddLilHermesInstrumentation junto con la dependencia de
OpenTelemetry.Api (CVE-2026-40894). Reemplázala por AddSource con el mismo SourceName
que configuras en AddLilHermes:
// 1.x
.AddLilHermesInstrumentation("MiServicio")
// 2.0
.AddSource("MiServicio")
Si llamabas a AddLilHermesInstrumentation() sin argumento, el nombre era "LilHermes":
comprueba que coincida con tu SourceName; si no coincidía, las trazas de LilHermes no se
estaban exportando.
Métricas disponibles
| Métrica | Tipo | Descripción |
|---|---|---|
messages_published |
Counter | Mensajes publicados |
messages_consumed |
Counter | Mensajes consumidos |
messages_failed |
Counter | Mensajes fallidos |
publish_duration_ms |
Histogram | Duración de publicación |
Tags de trazas (OTel Semantic Conventions)
messaging.system,messaging.destination,messaging.routing_keymessaging.message_id,messaging.correlation_idrabbitmq.exchange,rabbitmq.queue
La propagación de contexto usa el estándar W3C Trace Context (traceparent / tracestate) a través de los headers AMQP.
Comandos de desarrollo
# Compilar la solución
dotnet build LilHermes.sln
# Ejecutar todos los tests
dotnet test LilHermes.sln
# Solo tests unitarios
dotnet test test/LilHermes.UnitTests/LilHermes.UnitTests.csproj
# Solo tests de integración (requiere RabbitMQ + colector OTLP en localhost:4318)
dotnet test test/LilHermes.IntegrationTests/LilHermes.IntegrationTests.csproj
# Filtrar por nombre de test
dotnet test LilHermes.sln --filter "FullyQualifiedName~NombreDelTest"
# Generar paquetes NuGet
dotnet pack LilHermes.sln
Tests
| Proyecto | Target | Requisitos |
|---|---|---|
LilHermes.UnitTests |
net8.0 |
Ninguno |
LilHermes.IntegrationTests |
net8.0 |
RabbitMQ + OTLP en localhost:4318 |
Para levantar RabbitMQ rápidamente con Docker:
docker run -d --name rabbitmq \
-p 5672:5672 -p 15672:15672 \
rabbitmq:3-management
Panel de administración disponible en http://localhost:15672 (guest/guest).
Estructura del proyecto
LilHermes/
├── src/
│ ├── LilHermes.Abstractions/ # Contratos y modelos
│ │ ├── Entities/ # MessageBusOptions, MessageContext<T>, etc.
│ │ └── Enums/ # RabbitMQExchangeType, AcknowledgeMode, MessagePriority
│ └── LilHermes.Infrastructure/ # Implementaciones
│ ├── Connections/ # RabbitMQConnectionManager
│ ├── Publishers/ # RabbitMQPublisher
│ ├── Consumers/ # RabbitMQConsumer
│ ├── Extensions/ # LilHermesExtensions (DI)
│ └── Telemetry/ # ActivitySource, Meter, propagación W3C
└── test/
├── LilHermes.UnitTests/
└── LilHermes.IntegrationTests/
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- LilHermes.Abstractions (>= 2.1.0)
- Microsoft.Bcl.AsyncInterfaces (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 6.0.0)
- Polly (>= 8.5.2)
- RabbitMQ.Client (>= 7.2.0)
- System.Diagnostics.DiagnosticSource (>= 8.0.1)
- System.Text.Json (>= 6.0.10)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
2.1.0 — nuevo MessageContext.Create(data, sourceService, messageId) para armar mensajes sin escribir el tipo genérico; reemplaza los MessageContextFactory propios de cada servicio. MessageContext<T>.Timestamp ahora se genera en UTC (antes hora local); el header AMQP no cambia.