diff --git a/docs/src/content/docs/infra/azure-service-bus.md b/docs/src/content/docs/infra/azure-service-bus.md index 05819ba0..d6de2e1e 100644 --- a/docs/src/content/docs/infra/azure-service-bus.md +++ b/docs/src/content/docs/infra/azure-service-bus.md @@ -39,14 +39,15 @@ Producer options: When producing messages, you can supply per-message options using `ServiceBusProduceOptions`: -| Option | Description | -|--------------------|----------------------------------------------------------| -| `Subject` | Message subject | -| `To` | Forward-to address | -| `ReplyTo` | Reply-to address | -| `SessionId` | Session id for session-enabled queues/topics | -| `ReplyToSessionId` | Reply-to session id | -| `TimeToLive` | Message time-to-live, default is `TimeSpan.MaxValue` | +| Option | Description | +|------------------------|--------------------------------------------------------------------| +| `Subject` | Message subject | +| `To` | Forward-to address | +| `ReplyTo` | Reply-to address | +| `SessionId` | Session id for session-enabled queues/topics | +| `ReplyToSessionId` | Reply-to session id | +| `TimeToLive` | Message time-to-live, default is `TimeSpan.MaxValue` | +| `ScheduledEnqueueTime` | Datetime when service bus makes the message available to receivers | Message metadata is mapped to Azure Service Bus application properties. The attribute names used for standard properties (message type, stream name, correlation id, etc.) can be customized via `ServiceBusMessageAttributeNames`. diff --git a/docs/src/content/docs/next/infra/azure-service-bus.md b/docs/src/content/docs/next/infra/azure-service-bus.md index 05819ba0..d6de2e1e 100644 --- a/docs/src/content/docs/next/infra/azure-service-bus.md +++ b/docs/src/content/docs/next/infra/azure-service-bus.md @@ -39,14 +39,15 @@ Producer options: When producing messages, you can supply per-message options using `ServiceBusProduceOptions`: -| Option | Description | -|--------------------|----------------------------------------------------------| -| `Subject` | Message subject | -| `To` | Forward-to address | -| `ReplyTo` | Reply-to address | -| `SessionId` | Session id for session-enabled queues/topics | -| `ReplyToSessionId` | Reply-to session id | -| `TimeToLive` | Message time-to-live, default is `TimeSpan.MaxValue` | +| Option | Description | +|------------------------|--------------------------------------------------------------------| +| `Subject` | Message subject | +| `To` | Forward-to address | +| `ReplyTo` | Reply-to address | +| `SessionId` | Session id for session-enabled queues/topics | +| `ReplyToSessionId` | Reply-to session id | +| `TimeToLive` | Message time-to-live, default is `TimeSpan.MaxValue` | +| `ScheduledEnqueueTime` | Datetime when service bus makes the message available to receivers | Message metadata is mapped to Azure Service Bus application properties. The attribute names used for standard properties (message type, stream name, correlation id, etc.) can be customized via `ServiceBusMessageAttributeNames`. diff --git a/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusMessageBuilder.cs b/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusMessageBuilder.cs index 796ad53e..1924379e 100644 --- a/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusMessageBuilder.cs +++ b/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusMessageBuilder.cs @@ -39,6 +39,10 @@ internal ServiceBusMessage CreateServiceBusMessage(ProducedMessage message) { ReplyToSessionId = options?.ReplyToSessionId }; + if (options?.ScheduledEnqueueTime is {} scheduledEnqueueTime) { + serviceBusMessage.ScheduledEnqueueTime = scheduledEnqueueTime; + } + // We set the SessionId only when a value is present because // it overrides the PartitionKey, even if the SessionId is null. diff --git a/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProduceOptions.cs b/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProduceOptions.cs index 119ea98d..8c94cb57 100644 --- a/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProduceOptions.cs +++ b/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProduceOptions.cs @@ -36,4 +36,9 @@ public class ServiceBusProduceOptions { /// Gets or sets the time interval after which the message expires. /// public TimeSpan TimeToLive { get; set; } = TimeSpan.MaxValue; -} \ No newline at end of file + + /// + /// Gets or sets the date and time, in UTC, when service bus makes the message available to receivers + /// + public DateTimeOffset? ScheduledEnqueueTime { get; set; } +} diff --git a/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/ConvertEventToMessage.cs b/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/ConvertEventToMessage.cs index 9abd8e54..2ae6c1ac 100644 --- a/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/ConvertEventToMessage.cs +++ b/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/ConvertEventToMessage.cs @@ -4,7 +4,7 @@ namespace Eventuous.Tests.Azure.ServiceBus; public class ConvertEventToMessage { - readonly Guid _messageId = Guid.NewGuid(); + readonly Guid _messageId = Guid.NewGuid(); readonly ServiceBusMessage _message; public ConvertEventToMessage() { @@ -13,23 +13,24 @@ public ConvertEventToMessage() { "test-stream", new(), new() { - Subject = "test-subject", - To = "test-to", - ReplyTo = "test-reply-to", - TimeToLive = TimeSpan.FromMinutes(5) + Subject = "test-subject", + To = "test-to", + ReplyTo = "test-reply-to", + TimeToLive = TimeSpan.FromMinutes(5), + ScheduledEnqueueTime = new DateTimeOffset(2026, 3, 23, 16, 31, 0, TimeSpan.Zero) } ); _message = builder.CreateServiceBusMessage( new( new SomeEvent { - Id = "event-id", + Id = "event-id", Name = "Test Event" }, new() { [MetaTags.CorrelationId] = "correlation-id", - [MetaTags.CausationId] = "causation-id", - ["AAA"] = 1111 + [MetaTags.CausationId] = "causation-id", + ["AAA"] = 1111 }, new() { ["BBB"] = "12345" }, _messageId @@ -72,6 +73,10 @@ public async Task CorrelationId() { await Assert.That(_message.CorrelationId).IsEqualTo("correlation-id"); } + [Test] + public async Task ScheduledEnqueueTime() => + await Assert.That(_message.ScheduledEnqueueTime).IsEqualTo(new DateTimeOffset(2026, 3, 23, 16, 31, 0, TimeSpan.Zero)); + [Test] [Arguments("MessageId")] [Arguments("CorrelationId")] @@ -92,21 +97,21 @@ public class WithMessagePropertiesInMetaData { public WithMessagePropertiesInMetaData() { var attributeNames = new ServiceBusMessageAttributeNames(); - var builder = new ServiceBusMessageBuilder(DefaultEventSerializer.Instance, "test-stream", attributeNames, new()); + var builder = new ServiceBusMessageBuilder(DefaultEventSerializer.Instance, "test-stream", attributeNames, new()); _message = builder.CreateServiceBusMessage( new( new SomeEvent { - Id = "event-id", + Id = "event-id", Name = "Test Event" }, new() { - [attributeNames.MessageId] = "12345", + [attributeNames.MessageId] = "12345", [attributeNames.CorrelationId] = "correlation-id", - [attributeNames.CausationId] = "causation-id", - [attributeNames.ReplyTo] = "test-reply-to", - [attributeNames.Subject] = "test-subject", - [attributeNames.To] = "test-to" + [attributeNames.CausationId] = "causation-id", + [attributeNames.ReplyTo] = "test-reply-to", + [attributeNames.Subject] = "test-subject", + [attributeNames.To] = "test-to" }, new() )