Skip to content

Commit f8ac3bc

Browse files
Support ASB Native AutoDeleteOnIdle Setting
2 parents 62d6960 + 8159fb6 commit f8ac3bc

14 files changed

+476
-6
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
namespace NServiceBus.Transport.AzureServiceBus.AcceptanceTests
2+
{
3+
using System;
4+
using System.Threading.Tasks;
5+
using AcceptanceTesting;
6+
using Azure.Messaging.ServiceBus;
7+
using Azure.Messaging.ServiceBus.Administration;
8+
using NServiceBus.AcceptanceTests;
9+
using NServiceBus.AcceptanceTests.EndpointTemplates;
10+
using NUnit.Framework;
11+
12+
public class When_using_auto_delete_on_idle : NServiceBusAcceptanceTest
13+
{
14+
const string HasAutoDeleteOnIdleEndpointInstanceName = "usingautodeleteonidle.endpointwithautodeleteonidle-12345";
15+
const string NoAutoDeleteOnIdleEndpointInstanceName = "usingautodeleteonidle.endpointwithoutautodeleteonidle";
16+
const string HasAutoDeleteOnIdleButNoInstancesEndpointName = "usingautodeleteonidle.endpointwithautodeleteonidlebutnoinstances";
17+
18+
[SetUp]
19+
public async Task Setup()
20+
{
21+
var adminClient =
22+
new ServiceBusAdministrationClient(
23+
Environment.GetEnvironmentVariable("AzureServiceBus_ConnectionString"));
24+
try
25+
{
26+
// makes sure during local development the topic gets cleared before each test run
27+
await adminClient.DeleteQueueAsync(HasAutoDeleteOnIdleEndpointInstanceName);
28+
await adminClient.DeleteQueueAsync(NoAutoDeleteOnIdleEndpointInstanceName);
29+
await adminClient.DeleteQueueAsync(HasAutoDeleteOnIdleButNoInstancesEndpointName);
30+
}
31+
catch (ServiceBusException ex) when (ex.Reason == ServiceBusFailureReason.MessagingEntityNotFound)
32+
{
33+
}
34+
}
35+
36+
[Test]
37+
public async Task Should_configure_queue_with_auto_delete_on_idle()
38+
{
39+
var instanceId = "12345";
40+
var context = await Scenario.Define<Context>()
41+
.WithEndpoint<EndpointWithAutoDeleteOnIdle>(b =>
42+
{
43+
b.CustomConfig(c =>
44+
{
45+
var transport = c.ConfigureTransport<AzureServiceBusTransport>();
46+
transport.AutoDeleteOnIdle = TimeSpan.FromMinutes(10);
47+
c.MakeInstanceUniquelyAddressable(instanceId);
48+
});
49+
})
50+
.Done(c => c.EndpointsStarted)
51+
.Run();
52+
53+
// Verify that the queue was created with the correct AutoDeleteOnIdle setting
54+
var adminClient = new ServiceBusAdministrationClient(
55+
Environment.GetEnvironmentVariable("AzureServiceBus_ConnectionString"));
56+
57+
var queueProperties = await adminClient.GetQueueAsync(HasAutoDeleteOnIdleEndpointInstanceName);
58+
59+
Assert.That(queueProperties.Value.AutoDeleteOnIdle, Is.EqualTo(TimeSpan.FromMinutes(10)));
60+
}
61+
62+
[Test]
63+
public async Task Should_not_configure_queue_with_auto_delete_on_idle()
64+
{
65+
var context = await Scenario.Define<Context>()
66+
.WithEndpoint<EndpointWithoutAutoDeleteOnIdle>(b =>
67+
{
68+
b.CustomConfig(c =>
69+
{
70+
c.ConfigureTransport<AzureServiceBusTransport>();
71+
});
72+
})
73+
.Done(c => c.EndpointsStarted)
74+
.Run();
75+
76+
// Verify that the queue was created with the correct AutoDeleteOnIdle setting
77+
var adminClient = new ServiceBusAdministrationClient(
78+
Environment.GetEnvironmentVariable("AzureServiceBus_ConnectionString"));
79+
80+
var queueProperties = await adminClient.GetQueueAsync(NoAutoDeleteOnIdleEndpointInstanceName);
81+
82+
Assert.That(queueProperties.Value.AutoDeleteOnIdle, Is.EqualTo(TimeSpan.MaxValue));
83+
}
84+
85+
[Test]
86+
public async Task Should_not_configure_queue_with_auto_delete_on_idle_if_no_unique_instances()
87+
{
88+
var context = await Scenario.Define<Context>()
89+
.WithEndpoint<EndpointWithAutoDeleteOnIdleButNoInstances>(b =>
90+
{
91+
b.CustomConfig(c =>
92+
{
93+
var transport = c.ConfigureTransport<AzureServiceBusTransport>();
94+
transport.AutoDeleteOnIdle = TimeSpan.FromMinutes(10);
95+
});
96+
})
97+
.Done(c => c.EndpointsStarted)
98+
.Run();
99+
100+
// Verify that the queue was created with the correct AutoDeleteOnIdle setting
101+
var adminClient = new ServiceBusAdministrationClient(
102+
Environment.GetEnvironmentVariable("AzureServiceBus_ConnectionString"));
103+
104+
var queueProperties = await adminClient.GetQueueAsync(HasAutoDeleteOnIdleButNoInstancesEndpointName);
105+
106+
Assert.That(queueProperties.Value.AutoDeleteOnIdle, Is.EqualTo(TimeSpan.MaxValue));
107+
}
108+
109+
110+
public class Context : ScenarioContext
111+
{
112+
}
113+
114+
public class EndpointWithAutoDeleteOnIdle : EndpointConfigurationBuilder
115+
{
116+
public EndpointWithAutoDeleteOnIdle()
117+
{
118+
EndpointSetup<DefaultServer>();
119+
}
120+
}
121+
122+
public class EndpointWithoutAutoDeleteOnIdle : EndpointConfigurationBuilder
123+
{
124+
public EndpointWithoutAutoDeleteOnIdle()
125+
{
126+
EndpointSetup<DefaultServer>();
127+
}
128+
}
129+
130+
public class EndpointWithAutoDeleteOnIdleButNoInstances : EndpointConfigurationBuilder
131+
{
132+
public EndpointWithAutoDeleteOnIdleButNoInstances()
133+
{
134+
EndpointSetup<DefaultServer>();
135+
}
136+
}
137+
}
138+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
namespace NServiceBus.Transport.AzureServiceBus.Tests.Administration;
2+
3+
using System;
4+
using System.Threading.Tasks;
5+
using NUnit.Framework;
6+
using Particular.Approvals;
7+
8+
[TestFixture]
9+
public class QueueCreatorTests
10+
{
11+
[Test]
12+
public async Task Should_set_AutoDeleteOnIdle_when_configured()
13+
{
14+
var transport = new AzureServiceBusTransport("connectionString", TopicTopology.Default)
15+
{
16+
AutoDeleteOnIdle = TimeSpan.FromMinutes(10)
17+
};
18+
19+
var recordingClient = new RecordingServiceBusAdministrationClient();
20+
var creator = new QueueCreator(transport);
21+
22+
await creator.Create(recordingClient, ["test-queue"], "test-queue");
23+
24+
var output = recordingClient.ToString();
25+
26+
Approver.Verify(output);
27+
}
28+
29+
[Test]
30+
public async Task Should_not_set_AutoDeleteOnIdle_when_null()
31+
{
32+
var transport = new AzureServiceBusTransport("connectionString", TopicTopology.Default)
33+
{
34+
AutoDeleteOnIdle = null
35+
};
36+
37+
var recordingClient = new RecordingServiceBusAdministrationClient();
38+
var creator = new QueueCreator(transport);
39+
40+
await creator.Create(recordingClient, ["test-queue"], "test-queue");
41+
42+
var output = recordingClient.ToString(); // AutoDeleteOnIdle should be default - TimeSpan.MaxValue
43+
44+
Approver.Verify(output);
45+
}
46+
47+
[Test]
48+
public async Task Should_only_set_AutoDeleteOnIdle_on_instance_specific_queue()
49+
{
50+
var transport = new AzureServiceBusTransport("connectionString", TopicTopology.Default)
51+
{
52+
AutoDeleteOnIdle = TimeSpan.FromMinutes(10)
53+
};
54+
55+
var recordingClient = new RecordingServiceBusAdministrationClient();
56+
var creator = new QueueCreator(transport);
57+
58+
await creator.Create(recordingClient, ["instance-queue", "error"], "instance-queue");
59+
60+
// AutoDeleteOnIdle should be default for shared queues - TimeSpan.MaxValue
61+
var output = recordingClient.ToString();
62+
63+
Approver.Verify(output);
64+
}
65+
66+
[Test]
67+
public async Task Should_not_set_AutoDeleteOnIdle_when_instance_name_is_null()
68+
{
69+
var transport = new AzureServiceBusTransport("connectionString", TopicTopology.Default)
70+
{
71+
AutoDeleteOnIdle = TimeSpan.FromMinutes(10)
72+
};
73+
74+
var recordingClient = new RecordingServiceBusAdministrationClient();
75+
var creator = new QueueCreator(transport);
76+
77+
// Create queue without specifying an instance name
78+
await creator.Create(recordingClient, ["some-queue"], null);
79+
80+
var output = recordingClient.ToString();
81+
82+
Approver.Verify(output);
83+
}
84+
85+
[Test]
86+
public async Task Should_not_set_AutoDeleteOnIdle_when_queue_name_does_not_match_instance_name()
87+
{
88+
var transport = new AzureServiceBusTransport("connectionString", TopicTopology.Default)
89+
{
90+
AutoDeleteOnIdle = TimeSpan.FromMinutes(10)
91+
};
92+
93+
var recordingClient = new RecordingServiceBusAdministrationClient();
94+
var creator = new QueueCreator(transport);
95+
96+
// Create queue with different instance name
97+
await creator.Create(recordingClient, ["some-queue"], "different-instance");
98+
99+
var output = recordingClient.ToString();
100+
101+
Approver.Verify(output);
102+
}
103+
}

src/Tests/ApprovalFiles/APIApprovals.Approve.approved.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace NServiceBus
77
{
88
public AzureServiceBusTransport(string connectionString, NServiceBus.TopicTopology topology) { }
99
public AzureServiceBusTransport(string fullyQualifiedNamespace, Azure.Core.TokenCredential tokenCredential, NServiceBus.TopicTopology topology) { }
10+
public System.TimeSpan? AutoDeleteOnIdle { get; set; }
1011
public bool EnablePartitioning { get; set; }
1112
public int EntityMaximumSize { get; set; }
1213
public System.TimeSpan? MaxAutoLockRenewalDuration { get; set; }
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CreateQueueOptions: {
2+
"Name": "some-queue",
3+
"LockDuration": "00:05:00",
4+
"MaxSizeInMegabytes": 5120,
5+
"RequiresDuplicateDetection": false,
6+
"RequiresSession": false,
7+
"DefaultMessageTimeToLive": "10675199.02:48:05.4775807",
8+
"AutoDeleteOnIdle": "10675199.02:48:05.4775807",
9+
"DeadLetteringOnMessageExpiration": false,
10+
"DuplicateDetectionHistoryTimeWindow": "00:01:00",
11+
"MaxDeliveryCount": 2147483647,
12+
"EnableBatchedOperations": true,
13+
"AuthorizationRules": [],
14+
"Status": {},
15+
"ForwardTo": null,
16+
"ForwardDeadLetteredMessagesTo": null,
17+
"EnablePartitioning": false,
18+
"UserMetadata": null,
19+
"MaxMessageSizeInKilobytes": null
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CreateQueueOptions: {
2+
"Name": "test-queue",
3+
"LockDuration": "00:05:00",
4+
"MaxSizeInMegabytes": 5120,
5+
"RequiresDuplicateDetection": false,
6+
"RequiresSession": false,
7+
"DefaultMessageTimeToLive": "10675199.02:48:05.4775807",
8+
"AutoDeleteOnIdle": "10675199.02:48:05.4775807",
9+
"DeadLetteringOnMessageExpiration": false,
10+
"DuplicateDetectionHistoryTimeWindow": "00:01:00",
11+
"MaxDeliveryCount": 2147483647,
12+
"EnableBatchedOperations": true,
13+
"AuthorizationRules": [],
14+
"Status": {},
15+
"ForwardTo": null,
16+
"ForwardDeadLetteredMessagesTo": null,
17+
"EnablePartitioning": false,
18+
"UserMetadata": null,
19+
"MaxMessageSizeInKilobytes": null
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CreateQueueOptions: {
2+
"Name": "some-queue",
3+
"LockDuration": "00:05:00",
4+
"MaxSizeInMegabytes": 5120,
5+
"RequiresDuplicateDetection": false,
6+
"RequiresSession": false,
7+
"DefaultMessageTimeToLive": "10675199.02:48:05.4775807",
8+
"AutoDeleteOnIdle": "10675199.02:48:05.4775807",
9+
"DeadLetteringOnMessageExpiration": false,
10+
"DuplicateDetectionHistoryTimeWindow": "00:01:00",
11+
"MaxDeliveryCount": 2147483647,
12+
"EnableBatchedOperations": true,
13+
"AuthorizationRules": [],
14+
"Status": {},
15+
"ForwardTo": null,
16+
"ForwardDeadLetteredMessagesTo": null,
17+
"EnablePartitioning": false,
18+
"UserMetadata": null,
19+
"MaxMessageSizeInKilobytes": null
20+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
CreateQueueOptions: {
2+
"Name": "instance-queue",
3+
"LockDuration": "00:05:00",
4+
"MaxSizeInMegabytes": 5120,
5+
"RequiresDuplicateDetection": false,
6+
"RequiresSession": false,
7+
"DefaultMessageTimeToLive": "10675199.02:48:05.4775807",
8+
"AutoDeleteOnIdle": "00:10:00",
9+
"DeadLetteringOnMessageExpiration": false,
10+
"DuplicateDetectionHistoryTimeWindow": "00:01:00",
11+
"MaxDeliveryCount": 2147483647,
12+
"EnableBatchedOperations": true,
13+
"AuthorizationRules": [],
14+
"Status": {},
15+
"ForwardTo": null,
16+
"ForwardDeadLetteredMessagesTo": null,
17+
"EnablePartitioning": false,
18+
"UserMetadata": null,
19+
"MaxMessageSizeInKilobytes": null
20+
}
21+
CreateQueueOptions: {
22+
"Name": "error",
23+
"LockDuration": "00:05:00",
24+
"MaxSizeInMegabytes": 5120,
25+
"RequiresDuplicateDetection": false,
26+
"RequiresSession": false,
27+
"DefaultMessageTimeToLive": "10675199.02:48:05.4775807",
28+
"AutoDeleteOnIdle": "10675199.02:48:05.4775807",
29+
"DeadLetteringOnMessageExpiration": false,
30+
"DuplicateDetectionHistoryTimeWindow": "00:01:00",
31+
"MaxDeliveryCount": 2147483647,
32+
"EnableBatchedOperations": true,
33+
"AuthorizationRules": [],
34+
"Status": {},
35+
"ForwardTo": null,
36+
"ForwardDeadLetteredMessagesTo": null,
37+
"EnablePartitioning": false,
38+
"UserMetadata": null,
39+
"MaxMessageSizeInKilobytes": null
40+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CreateQueueOptions: {
2+
"Name": "test-queue",
3+
"LockDuration": "00:05:00",
4+
"MaxSizeInMegabytes": 5120,
5+
"RequiresDuplicateDetection": false,
6+
"RequiresSession": false,
7+
"DefaultMessageTimeToLive": "10675199.02:48:05.4775807",
8+
"AutoDeleteOnIdle": "00:10:00",
9+
"DeadLetteringOnMessageExpiration": false,
10+
"DuplicateDetectionHistoryTimeWindow": "00:01:00",
11+
"MaxDeliveryCount": 2147483647,
12+
"EnableBatchedOperations": true,
13+
"AuthorizationRules": [],
14+
"Status": {},
15+
"ForwardTo": null,
16+
"ForwardDeadLetteredMessagesTo": null,
17+
"EnablePartitioning": false,
18+
"UserMetadata": null,
19+
"MaxMessageSizeInKilobytes": null
20+
}

0 commit comments

Comments
 (0)