From 813451743fb239667b874451aff38b138d819253 Mon Sep 17 00:00:00 2001 From: "Jeremy D. Miller" Date: Thu, 12 Feb 2026 09:02:23 -0600 Subject: [PATCH] Centralize DLQ constants into DeadLetterQueueConstants Extract repeated dead letter queue name and exception header strings into a shared DeadLetterQueueConstants class so all transports reference a single source of truth. Co-Authored-By: Claude Opus 4.6 --- .../Internal/AmazonSqsTransport.cs | 2 +- .../AzureServiceBusTransport.cs | 2 +- .../Internals/KafkaListener.cs | 8 ++--- .../Internals/KafkaTransport.cs | 2 +- .../Internal/RabbitMqTransport.cs | 2 +- .../Internal/RedisStreamListener.cs | 8 ++--- .../Transports/DeadLetterQueueConstants.cs | 29 +++++++++++++++++++ 7 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 src/Wolverine/Transports/DeadLetterQueueConstants.cs diff --git a/src/Transports/AWS/Wolverine.AmazonSqs/Internal/AmazonSqsTransport.cs b/src/Transports/AWS/Wolverine.AmazonSqs/Internal/AmazonSqsTransport.cs index fe1bc38e9..30f84fe87 100644 --- a/src/Transports/AWS/Wolverine.AmazonSqs/Internal/AmazonSqsTransport.cs +++ b/src/Transports/AWS/Wolverine.AmazonSqs/Internal/AmazonSqsTransport.cs @@ -11,7 +11,7 @@ namespace Wolverine.AmazonSqs.Internal; public class AmazonSqsTransport : BrokerTransport { - public const string DeadLetterQueueName = "wolverine-dead-letter-queue"; + public const string DeadLetterQueueName = DeadLetterQueueConstants.DefaultQueueName; public const char Separator = '-'; diff --git a/src/Transports/Azure/Wolverine.AzureServiceBus/AzureServiceBusTransport.cs b/src/Transports/Azure/Wolverine.AzureServiceBus/AzureServiceBusTransport.cs index c057697cc..ccf6f1e24 100644 --- a/src/Transports/Azure/Wolverine.AzureServiceBus/AzureServiceBusTransport.cs +++ b/src/Transports/Azure/Wolverine.AzureServiceBus/AzureServiceBusTransport.cs @@ -22,7 +22,7 @@ public partial class AzureServiceBusTransport : BrokerTransport Subscriptions = new(); private string _hostName; - public const string DeadLetterQueueName = "wolverine-dead-letter-queue"; + public const string DeadLetterQueueName = DeadLetterQueueConstants.DefaultQueueName; public AzureServiceBusTransport() : this(ProtocolName) { diff --git a/src/Transports/Kafka/Wolverine.Kafka/Internals/KafkaListener.cs b/src/Transports/Kafka/Wolverine.Kafka/Internals/KafkaListener.cs index 7c578d4b4..3221bfdeb 100644 --- a/src/Transports/Kafka/Wolverine.Kafka/Internals/KafkaListener.cs +++ b/src/Transports/Kafka/Wolverine.Kafka/Internals/KafkaListener.cs @@ -154,10 +154,10 @@ public async Task MoveToErrorsAsync(Envelope envelope, Exception exception) var message = await _endpoint.EnvelopeMapper!.CreateMessage(envelope); message.Headers ??= new Headers(); - message.Headers.Add("exception-type", Encoding.UTF8.GetBytes(exception.GetType().FullName ?? "Unknown")); - message.Headers.Add("exception-message", Encoding.UTF8.GetBytes(exception.Message)); - message.Headers.Add("exception-stack", Encoding.UTF8.GetBytes(exception.StackTrace ?? "")); - message.Headers.Add("failed-at", Encoding.UTF8.GetBytes(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString())); + message.Headers.Add(DeadLetterQueueConstants.ExceptionTypeHeader, Encoding.UTF8.GetBytes(exception.GetType().FullName ?? "Unknown")); + message.Headers.Add(DeadLetterQueueConstants.ExceptionMessageHeader, Encoding.UTF8.GetBytes(exception.Message)); + message.Headers.Add(DeadLetterQueueConstants.ExceptionStackHeader, Encoding.UTF8.GetBytes(exception.StackTrace ?? "")); + message.Headers.Add(DeadLetterQueueConstants.FailedAtHeader, Encoding.UTF8.GetBytes(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString())); using var producer = transport.CreateProducer(_endpoint.GetEffectiveProducerConfig()); await producer.ProduceAsync(dlqTopicName, message); diff --git a/src/Transports/Kafka/Wolverine.Kafka/Internals/KafkaTransport.cs b/src/Transports/Kafka/Wolverine.Kafka/Internals/KafkaTransport.cs index 35d93645c..77ee29d4d 100644 --- a/src/Transports/Kafka/Wolverine.Kafka/Internals/KafkaTransport.cs +++ b/src/Transports/Kafka/Wolverine.Kafka/Internals/KafkaTransport.cs @@ -41,7 +41,7 @@ public KafkaTransport(string protocol) : base(protocol, "Kafka Topics", ["kafka" /// The Kafka topic name used for native dead letter queue messages. /// Default is "wolverine-dead-letter-queue". /// - public string DeadLetterQueueTopicName { get; set; } = "wolverine-dead-letter-queue"; + public string DeadLetterQueueTopicName { get; set; } = DeadLetterQueueConstants.DefaultQueueName; public KafkaUsage Usage { get; set; } = KafkaUsage.ProduceAndConsume; diff --git a/src/Transports/RabbitMQ/Wolverine.RabbitMQ/Internal/RabbitMqTransport.cs b/src/Transports/RabbitMQ/Wolverine.RabbitMQ/Internal/RabbitMqTransport.cs index accc65bb0..971ee0686 100644 --- a/src/Transports/RabbitMQ/Wolverine.RabbitMQ/Internal/RabbitMqTransport.cs +++ b/src/Transports/RabbitMQ/Wolverine.RabbitMQ/Internal/RabbitMqTransport.cs @@ -16,7 +16,7 @@ public partial class RabbitMqTransport : BrokerTransport, IAsy { public const string ProtocolName = "rabbitmq"; public const string ResponseEndpointName = "RabbitMqResponses"; - public const string DeadLetterQueueName = "wolverine-dead-letter-queue"; + public const string DeadLetterQueueName = DeadLetterQueueConstants.DefaultQueueName; public const string DeadLetterQueueHeader = "x-dead-letter-exchange"; public const string QueueTypeHeader = "x-queue-type"; diff --git a/src/Transports/Redis/Wolverine.Redis/Internal/RedisStreamListener.cs b/src/Transports/Redis/Wolverine.Redis/Internal/RedisStreamListener.cs index f90b5901b..076a55b6b 100644 --- a/src/Transports/Redis/Wolverine.Redis/Internal/RedisStreamListener.cs +++ b/src/Transports/Redis/Wolverine.Redis/Internal/RedisStreamListener.cs @@ -66,10 +66,10 @@ public async Task MoveToErrorsAsync(Envelope envelope, Exception exception) var fields = new List { new("envelope", serializedEnvelope), - new("exception-type", exception.GetType().FullName ?? "Unknown"), - new("exception-message", exception.Message ?? ""), - new("exception-stack", exception.StackTrace ?? ""), - new("failed-at", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString()), + new(DeadLetterQueueConstants.ExceptionTypeHeader, exception.GetType().FullName ?? "Unknown"), + new(DeadLetterQueueConstants.ExceptionMessageHeader, exception.Message ?? ""), + new(DeadLetterQueueConstants.ExceptionStackHeader, exception.StackTrace ?? ""), + new(DeadLetterQueueConstants.FailedAtHeader, DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString()), new("message-type", envelope.MessageType ?? "Unknown"), new("envelope-id", envelope.Id.ToString()), new("attempts", envelope.Attempts.ToString()) diff --git a/src/Wolverine/Transports/DeadLetterQueueConstants.cs b/src/Wolverine/Transports/DeadLetterQueueConstants.cs new file mode 100644 index 000000000..e52e6b5c1 --- /dev/null +++ b/src/Wolverine/Transports/DeadLetterQueueConstants.cs @@ -0,0 +1,29 @@ +namespace Wolverine.Transports; + +public static class DeadLetterQueueConstants +{ + /// + /// The default queue/topic name used for dead letter queues across all transports. + /// + public const string DefaultQueueName = "wolverine-dead-letter-queue"; + + /// + /// Header key for the full type name of the exception that caused the message to fail. + /// + public const string ExceptionTypeHeader = "exception-type"; + + /// + /// Header key for the exception message. + /// + public const string ExceptionMessageHeader = "exception-message"; + + /// + /// Header key for the exception stack trace. + /// + public const string ExceptionStackHeader = "exception-stack"; + + /// + /// Header key for the Unix timestamp in milliseconds when the failure occurred. + /// + public const string FailedAtHeader = "failed-at"; +}