Skip to content

Commit 606a4a7

Browse files
committed
Allow to specify ASB specific consumer settings on handlers and request-response configuration.
Signed-off-by: Tomasz Maruszak <maruszaktomasz@gmail.com>
1 parent 5bbf82c commit 606a4a7

26 files changed

Lines changed: 381 additions & 445 deletions

src/Host.Transport.Properties.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<Import Project="Common.NuGet.Properties.xml" />
55

66
<PropertyGroup>
7-
<Version>2.1.7</Version>
7+
<Version>2.1.8</Version>
88
</PropertyGroup>
99

1010
</Project>

src/SlimMessageBus.Host.AsyncApi/MessageBusDocumentGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private static IDictionary<string, ChannelItem> GenerateChannels(AsyncApiSchemaR
8888
/// <returns></returns>
8989
private static string TryGetSubscriptionName(ConsumerSettings consumer) =>
9090
consumer.GetOrDefault<string>("Group")
91-
?? consumer.GetOrDefault<string>("SubscriptionName")
91+
?? consumer.GetOrDefault<string>("Asb_SubscriptionName")
9292
?? consumer.GetOrDefault<string>("Eh_Group");
9393

9494
private static void GenerateChannelsFromConsumers(IDictionary<string, ChannelItem> channels, AsyncApiSchemaResolver schemaResolver, AsyncApiOptions options, JsonSchemaGenerator jsonSchemaGenerator, IServiceProvider serviceProvider, MessageBusSettings messageBusSettings, NamedServer namedServer)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
namespace SlimMessageBus.Host.AzureServiceBus;
2+
3+
public static class AsbAbstractConsumerSettingsExtensions
4+
{
5+
internal static void SetSubscriptionName(this AbstractConsumerSettings consumerSettings, string subscriptionName)
6+
{
7+
if (subscriptionName is null) throw new ArgumentNullException(nameof(subscriptionName));
8+
9+
consumerSettings.Properties[AsbProperties.SubscriptionNameKey] = subscriptionName;
10+
}
11+
12+
internal static string GetSubscriptionName(this AbstractConsumerSettings consumerSettings, bool required = true)
13+
{
14+
if (!consumerSettings.Properties.ContainsKey(AsbProperties.SubscriptionNameKey) && !required)
15+
{
16+
return null;
17+
}
18+
return consumerSettings.Properties[AsbProperties.SubscriptionNameKey] as string;
19+
}
20+
21+
internal static void SetMaxAutoLockRenewalDuration(this AbstractConsumerSettings consumerSettings, TimeSpan duration)
22+
=> consumerSettings.Properties[AsbProperties.MaxAutoLockRenewalDurationKey] = duration;
23+
24+
internal static TimeSpan? GetMaxAutoLockRenewalDuration(this AbstractConsumerSettings consumerSettings)
25+
=> consumerSettings.GetOrDefault<TimeSpan?>(AsbProperties.MaxAutoLockRenewalDurationKey);
26+
27+
internal static void SetSubQueue(this AbstractConsumerSettings consumerSettings, SubQueue subQueue)
28+
=> consumerSettings.Properties[AsbProperties.SubQueueKey] = subQueue;
29+
30+
internal static SubQueue? GetSubQueue(this AbstractConsumerSettings consumerSettings)
31+
=> consumerSettings.GetOrDefault<SubQueue?>(AsbProperties.SubQueueKey);
32+
33+
internal static void SetPrefetchCount(this AbstractConsumerSettings consumerSettings, int prefetchCount)
34+
=> consumerSettings.Properties[AsbProperties.PrefetchCountKey] = prefetchCount;
35+
36+
internal static int? GetPrefetchCount(this AbstractConsumerSettings consumerSettings)
37+
=> consumerSettings.GetOrDefault<int?>(AsbProperties.PrefetchCountKey);
38+
39+
internal static void SetEnableSession(this AbstractConsumerSettings consumerSettings, bool enableSession)
40+
=> consumerSettings.Properties[AsbProperties.EnableSessionKey] = enableSession;
41+
42+
internal static bool GetEnableSession(this AbstractConsumerSettings consumerSettings)
43+
=> consumerSettings.GetOrDefault(AsbProperties.EnableSessionKey, false);
44+
45+
internal static void SetSessionIdleTimeout(this AbstractConsumerSettings consumerSettings, TimeSpan sessionIdleTimeout)
46+
=> consumerSettings.Properties[AsbProperties.SessionIdleTimeoutKey] = sessionIdleTimeout;
47+
48+
internal static TimeSpan? GetSessionIdleTimeout(this AbstractConsumerSettings consumerSettings)
49+
=> consumerSettings.GetOrDefault<TimeSpan?>(AsbProperties.SessionIdleTimeoutKey);
50+
51+
internal static void SetMaxConcurrentSessions(this AbstractConsumerSettings consumerSettings, int maxConcurrentSessions)
52+
=> consumerSettings.Properties[AsbProperties.MaxConcurrentSessionsKey] = maxConcurrentSessions;
53+
54+
internal static int? GetMaxConcurrentSessions(this AbstractConsumerSettings consumerSettings)
55+
=> consumerSettings.GetOrDefault<int?>(AsbProperties.MaxConcurrentSessionsKey);
56+
57+
internal static IDictionary<string, SubscriptionSqlRule> GetRules(this AbstractConsumerSettings consumerSettings, bool createIfNotExists = false)
58+
{
59+
var filterByName = consumerSettings.GetOrDefault<IDictionary<string, SubscriptionSqlRule>>(AsbProperties.RulesKey);
60+
if (filterByName == null && createIfNotExists)
61+
{
62+
filterByName = new Dictionary<string, SubscriptionSqlRule>();
63+
consumerSettings.Properties[AsbProperties.RulesKey] = filterByName;
64+
}
65+
return filterByName;
66+
}
67+
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
namespace SlimMessageBus.Host.AzureServiceBus;
2+
3+
using Azure.Messaging.ServiceBus;
4+
using Azure.Messaging.ServiceBus.Administration;
5+
6+
public static class AsbConsumerBuilderExtensions
7+
{
8+
/// <summary>
9+
/// Sets the queue name for this consumer to use.
10+
/// </summary>
11+
/// <typeparam name="TConsumerBuilder"></typeparam>
12+
/// <param name="builder"></param>
13+
/// <param name="queue"></param>
14+
/// <param name="queueConfig"></param>
15+
/// <returns></returns>
16+
/// <exception cref="ArgumentNullException"></exception>
17+
public static TConsumerBuilder Queue<TConsumerBuilder>(this TConsumerBuilder builder, string queue, Action<TConsumerBuilder> queueConfig = null)
18+
where TConsumerBuilder : AbstractConsumerBuilder
19+
{
20+
if (builder is null) throw new ArgumentNullException(nameof(builder));
21+
if (queue is null) throw new ArgumentNullException(nameof(queue));
22+
23+
builder.ConsumerSettings.Path = queue;
24+
builder.ConsumerSettings.PathKind = PathKind.Queue;
25+
26+
queueConfig?.Invoke(builder);
27+
28+
return builder;
29+
}
30+
31+
private static void AssertIsTopicForSubscriptionName(AbstractConsumerSettings settings)
32+
{
33+
if (settings is null) throw new ArgumentNullException(nameof(settings));
34+
35+
if (settings.PathKind == PathKind.Queue)
36+
{
37+
var methodName = $".{nameof(SubscriptionName)}(...)";
38+
39+
var messageType = settings is ConsumerSettings consumerSettings
40+
? consumerSettings.MessageType.FullName
41+
: string.Empty;
42+
43+
throw new ConfigurationMessageBusException($"The subscription name configuration ({methodName}) does not apply to Azure ServiceBus queues (it only applies to topic consumers). Remove the {methodName} configuration for type {messageType} and queue {settings.Path} or change the consumer configuration to consume from topic {settings.Path} instead.");
44+
}
45+
}
46+
47+
/// <summary>
48+
/// Configures the subscription name when consuming form Azure ServiceBus topic.
49+
/// Not applicable when consuming from Azure ServiceBus queue.
50+
/// </summary>
51+
/// <param name="builder"></param>
52+
/// <param name="subscriptionName"></param>
53+
/// <returns></returns>
54+
public static T SubscriptionName<T>(this T builder, string subscriptionName)
55+
where T : IAbstractConsumerBuilder
56+
{
57+
if (builder is null) throw new ArgumentNullException(nameof(builder));
58+
if (subscriptionName is null) throw new ArgumentNullException(nameof(subscriptionName));
59+
60+
AssertIsTopicForSubscriptionName(builder.ConsumerSettings);
61+
62+
builder.ConsumerSettings.SetSubscriptionName(subscriptionName);
63+
return builder;
64+
}
65+
66+
/// <summary>
67+
/// Azure Service Bus consumer setting. See underlying client for more details: https://docs.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.servicebusprocessoroptions.maxautolockrenewalduration
68+
/// </summary>
69+
/// <typeparam name="TConsumerBuilder"></typeparam>
70+
/// <param name="builder"></param>
71+
/// <param name="duration"></param>
72+
/// <returns></returns>
73+
/// <exception cref="ArgumentNullException"></exception>
74+
public static TConsumerBuilder MaxAutoLockRenewalDuration<TConsumerBuilder>(this TConsumerBuilder builder, TimeSpan duration)
75+
where TConsumerBuilder : IAbstractConsumerBuilder
76+
{
77+
if (builder is null) throw new ArgumentNullException(nameof(builder));
78+
79+
builder.ConsumerSettings.SetMaxAutoLockRenewalDuration(duration);
80+
81+
return builder;
82+
}
83+
84+
/// <summary>
85+
/// Azure Service Bus consumer setting. See underlying client for more details: https://docs.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.servicebusprocessoroptions.subqueue
86+
/// </summary>
87+
/// <typeparam name="TConsumerBuilder"></typeparam>
88+
/// <param name="builder"></param>
89+
/// <param name="subQueue"></param>
90+
/// <returns></returns>
91+
/// <exception cref="ArgumentNullException"></exception>
92+
public static TConsumerBuilder SubQueue<TConsumerBuilder>(this TConsumerBuilder builder, SubQueue subQueue)
93+
where TConsumerBuilder : IAbstractConsumerBuilder
94+
{
95+
if (builder is null) throw new ArgumentNullException(nameof(builder));
96+
97+
builder.ConsumerSettings.SetSubQueue(subQueue);
98+
99+
return builder;
100+
}
101+
102+
/// <summary>
103+
/// Azure Service Bus consumer setting. See underlying client for more details: https://docs.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.servicebusprocessoroptions.prefetchcount
104+
/// </summary>
105+
/// <typeparam name="TConsumerBuilder"></typeparam>
106+
/// <param name="builder"></param>
107+
/// <param name="prefetchCount "></param>
108+
/// <returns></returns>
109+
/// <exception cref="ArgumentNullException"></exception>
110+
public static TConsumerBuilder PrefetchCount<TConsumerBuilder>(this TConsumerBuilder builder, int prefetchCount)
111+
where TConsumerBuilder : IAbstractConsumerBuilder
112+
{
113+
if (builder is null) throw new ArgumentNullException(nameof(builder));
114+
115+
builder.ConsumerSettings.SetPrefetchCount(prefetchCount);
116+
117+
return builder;
118+
}
119+
120+
/// <summary>
121+
/// Enables Azue Service Bus session support for this consumer
122+
/// </summary>
123+
/// <typeparam name="TConsumerBuilder"></typeparam>
124+
/// <param name="builder"></param>
125+
/// <returns></returns>
126+
/// <exception cref="ArgumentNullException"></exception>
127+
public static TConsumerBuilder EnableSession<TConsumerBuilder>(this TConsumerBuilder builder, Action<AsbConsumerSessionBuilder> sessionConfiguration = null)
128+
where TConsumerBuilder : IAbstractConsumerBuilder
129+
{
130+
if (builder is null) throw new ArgumentNullException(nameof(builder));
131+
132+
builder.ConsumerSettings.SetEnableSession(true);
133+
134+
if (sessionConfiguration != null)
135+
{
136+
sessionConfiguration(new AsbConsumerSessionBuilder(builder.ConsumerSettings));
137+
}
138+
139+
return builder;
140+
}
141+
142+
/// <summary>
143+
/// Adds a named SQL filter to the subscription (Azure Service Bus). Setting relevant only if topology provisioning enabled.
144+
/// </summary>
145+
/// <typeparam name="TConsumerBuilder"></typeparam>
146+
/// <param name="builder"></param>
147+
/// <param name="ruleName">The name of the filter</param>
148+
/// <param name="filterSql">The SQL expression of the filter</param>
149+
/// <param name="actionSql">The action to be performed on the filter</param>
150+
/// <returns></returns>
151+
/// <exception cref="ArgumentNullException"></exception>
152+
public static TConsumerBuilder SubscriptionSqlFilter<TConsumerBuilder>(this TConsumerBuilder builder, string filterSql, string ruleName = "default", string actionSql = null)
153+
where TConsumerBuilder : IAbstractConsumerBuilder
154+
{
155+
if (builder is null) throw new ArgumentNullException(nameof(builder));
156+
157+
var filterByName = builder.ConsumerSettings.GetRules(createIfNotExists: true);
158+
filterByName[ruleName] = new SubscriptionSqlRule { Name = ruleName, SqlFilter = filterSql, SqlAction = actionSql };
159+
160+
return builder;
161+
}
162+
163+
/// <summary>
164+
/// <see cref="CreateQueueOptions"/> when the ASB queue does not exist and needs to be created
165+
/// </summary>
166+
/// <typeparam name="TConsumerBuilder"></typeparam>
167+
/// <param name="builder"></param>
168+
/// <returns></returns>
169+
public static TConsumerBuilder CreateQueueOptions<TConsumerBuilder>(this TConsumerBuilder builder, Action<CreateQueueOptions> action)
170+
where TConsumerBuilder : IAbstractConsumerBuilder
171+
{
172+
if (builder is null) throw new ArgumentNullException(nameof(builder));
173+
if (action is null) throw new ArgumentNullException(nameof(action));
174+
175+
builder.ConsumerSettings.SetQueueOptions(action);
176+
return builder;
177+
}
178+
179+
/// <summary>
180+
/// <see cref="CreateTopicOptions"/> when the ASB topic does not exist and needs to be created
181+
/// </summary>
182+
/// <typeparam name="TConsumerBuilder"></typeparam>
183+
/// <param name="builder"></param>
184+
/// <param name="action"></param>
185+
/// <returns></returns>
186+
public static TConsumerBuilder CreateTopicOptions<TConsumerBuilder>(this TConsumerBuilder builder, Action<CreateTopicOptions> action)
187+
where TConsumerBuilder : IAbstractConsumerBuilder
188+
{
189+
if (builder is null) throw new ArgumentNullException(nameof(builder));
190+
if (action is null) throw new ArgumentNullException(nameof(action));
191+
192+
builder.ConsumerSettings.SetTopicOptions(action);
193+
return builder;
194+
}
195+
196+
/// <summary>
197+
/// <see cref="CreateSubscriptionOptions"/> when the ASB subscription does not exist and needs to be created
198+
/// </summary>
199+
/// <typeparam name="TConsumerBuilder"></typeparam>
200+
/// <param name="builder"></param>
201+
/// <param name="action"></param>
202+
/// <returns></returns>
203+
public static TConsumerBuilder CreateSubscriptionOptions<TConsumerBuilder>(this TConsumerBuilder builder, Action<CreateSubscriptionOptions> action)
204+
where TConsumerBuilder : IAbstractConsumerBuilder
205+
{
206+
if (builder is null) throw new ArgumentNullException(nameof(builder));
207+
if (action is null) throw new ArgumentNullException(nameof(action));
208+
209+
builder.ConsumerSettings.SetSubscriptionOptions(action);
210+
return builder;
211+
}
212+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
namespace SlimMessageBus.Host.AzureServiceBus;
2+
3+
public class AsbConsumerSessionBuilder
4+
{
5+
internal AbstractConsumerSettings ConsumerSettings { get; }
6+
7+
public AsbConsumerSessionBuilder(AbstractConsumerSettings consumerSettings) => ConsumerSettings = consumerSettings;
8+
9+
/// <summary>
10+
/// Sets the Azue Service Bus session idle timeout.
11+
/// </summary>
12+
/// <param name="sessionIdleTimeout"></param>
13+
/// <returns></returns>
14+
public AsbConsumerSessionBuilder SessionIdleTimeout(TimeSpan sessionIdleTimeout)
15+
{
16+
ConsumerSettings.SetSessionIdleTimeout(sessionIdleTimeout);
17+
18+
return this;
19+
}
20+
21+
/// <summary>
22+
/// Sets the Azue Service Bus maximmum concurrent sessions that can be handled by this consumer.
23+
/// </summary>
24+
/// <param name="maxConcurrentSessions"></param>
25+
/// <returns></returns>
26+
public AsbConsumerSessionBuilder MaxConcurrentSessions(int maxConcurrentSessions)
27+
{
28+
ConsumerSettings.SetMaxConcurrentSessions(maxConcurrentSessions);
29+
30+
return this;
31+
}
32+
}

src/SlimMessageBus.Host.AzureServiceBus/Config/HasProviderExtensionsExtensions.cs renamed to src/SlimMessageBus.Host.AzureServiceBus/Config/AsbHasProviderExtensionsExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using Azure.Messaging.ServiceBus;
44
using Azure.Messaging.ServiceBus.Administration;
55

6-
internal static class HasProviderExtensionsExtensions
6+
internal static class AsbHasProviderExtensionsExtensions
77
{
88
internal static HasProviderExtensions SetMessageModifier(this HasProviderExtensions producerSettings, Action<object, ServiceBusMessage> messageModifierAction)
99
{

src/SlimMessageBus.Host.AzureServiceBus/Config/ProducerBuilderExtensions.cs renamed to src/SlimMessageBus.Host.AzureServiceBus/Config/AsbProducerBuilderExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
using Azure.Messaging.ServiceBus;
44
using Azure.Messaging.ServiceBus.Administration;
55

6-
public static class ProducerBuilderExtensions
6+
public static class AsbProducerBuilderExtensions
77
{
88
public static ProducerBuilder<T> DefaultQueue<T>(this ProducerBuilder<T> producerBuilder, string queue)
99
{
1010
if (producerBuilder is null) throw new ArgumentNullException(nameof(producerBuilder));
1111
if (queue is null) throw new ArgumentNullException(nameof(queue));
1212

13-
producerBuilder.DefaultTopic(queue);
13+
producerBuilder.DefaultPath(queue);
1414
producerBuilder.ToQueue();
1515
return producerBuilder;
1616
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace SlimMessageBus.Host.AzureServiceBus;
2+
3+
public static class AsbProperties
4+
{
5+
public static readonly string SubscriptionNameKey = "Asb_SubscriptionName";
6+
public static readonly string MaxAutoLockRenewalDurationKey = "Asb_MaxAutoLockRenewalDuration";
7+
public static readonly string SubQueueKey = "Asb_SubQueue";
8+
public static readonly string PrefetchCountKey = "Asb_PrefetchCount";
9+
public static readonly string EnableSessionKey = "Asb_SessionEnabled";
10+
public static readonly string SessionIdleTimeoutKey = "Asb_SessionIdleTimeout";
11+
public static readonly string MaxConcurrentSessionsKey = "Asb_MaxConcurrentSessions";
12+
public static readonly string RulesKey = "Asb_Rules";
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace SlimMessageBus.Host.AzureServiceBus;
2+
3+
public static class AsbRequestResponseBuilderExtensions
4+
{
5+
public static RequestResponseBuilder ReplyToQueue(this RequestResponseBuilder builder, string queue, Action<RequestResponseBuilder> builderConfig = null)
6+
{
7+
if (builder is null) throw new ArgumentNullException(nameof(builder));
8+
if (queue is null) throw new ArgumentNullException(nameof(queue));
9+
10+
builder.Settings.Path = queue;
11+
builder.Settings.PathKind = PathKind.Queue;
12+
13+
builderConfig?.Invoke(builder);
14+
15+
return builder;
16+
}
17+
}

0 commit comments

Comments
 (0)