Skip to content

Commit 5d7df2e

Browse files
authored
Add NServiceBus 10 Sample: delayed-delivery (#7596)
* Remove InputLoopService from delayed-delivery Core_9 sample and move logic back to Program class * Add Dockerfile and test script for delayed-delivery Core_9 sample * Add delayed-delivery Core_10 sample for NServiceBus 10 with .NET 10 and alpha packages * Apply C# 12+ language features to delayed-delivery Core_10 sample - Use collection expressions for List initialization - Improve string interpolation with direct format specifiers * Add Dockerfile for recoverabilitypolicytesting Core_9 sample - Added multi-stage Dockerfile that runs unit tests during build stage - Tests validate custom recoverability policy behavior: - Messages with MyBusinessTimedOutException are discarded - Unrecoverable exceptions go to custom error queue - Other exceptions go to default error queue - Simplified approach for unit testing sample (no console apps or startup script needed) * Add recoverabilitypolicytesting Core_10 sample for NServiceBus 10 - Updated to target .NET 10 with preview language features - Updated NServiceBus packages to latest alpha versions: - NServiceBus: 10.0.0-alpha.2 - NServiceBus.Testing: 10.0.0-alpha.3 - Updated Dockerfile for .NET 10 preview with required environment variable - Added prerelease.txt marker file - All unit tests pass, validating custom recoverability policy behavior * Apply C# 12 collection expressions to recoverabilitypolicytesting Core_10 - Use collection expressions for HashSet initialization: [typeof(DivideByZeroException)] - Use collection expressions for empty collections: [] instead of new HashSet<Type>() - Use collection expressions for empty byte arrays: [] instead of new byte[0] - Maintains same functionality with cleaner, more modern syntax - All tests continue to pass
1 parent a51c7bc commit 5d7df2e

25 files changed

+865
-68
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net10.0</TargetFramework>
4+
<OutputType>Exe</OutputType>
5+
<LangVersion>preview</LangVersion>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.1" />
9+
</ItemGroup>
10+
<ItemGroup>
11+
<ProjectReference Include="..\Shared\Shared.csproj" />
12+
</ItemGroup>
13+
</Project>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Hosting;
5+
using NServiceBus;
6+
7+
Console.Title = "Client";
8+
var builder = Host.CreateApplicationBuilder(args);
9+
10+
var endpointConfiguration = new EndpointConfiguration("Samples.DelayedDelivery.Client");
11+
endpointConfiguration.UsePersistence<LearningPersistence>();
12+
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
13+
endpointConfiguration.UseTransport(new LearningTransport());
14+
15+
builder.UseNServiceBus(endpointConfiguration);
16+
17+
var host = builder.Build();
18+
await host.StartAsync();
19+
20+
var messageSession = host.Services.GetRequiredService<IMessageSession>();
21+
await SendOrder(messageSession);
22+
23+
await host.StopAsync();
24+
25+
static async Task SendOrder(IMessageSession messageSession)
26+
{
27+
Console.WriteLine("Press '1' to send PlaceOrder - defer message handling");
28+
Console.WriteLine("Press '2' to send PlaceDelayedOrder - defer message delivery");
29+
Console.WriteLine("Press any other key to exit");
30+
31+
while (true)
32+
{
33+
var key = Console.ReadKey();
34+
Console.WriteLine();
35+
var id = Guid.NewGuid();
36+
37+
switch (key.Key)
38+
{
39+
case ConsoleKey.D1:
40+
case ConsoleKey.NumPad1:
41+
#region SendOrder
42+
var placeOrder = new PlaceOrder
43+
{
44+
Product = "New shoes",
45+
Id = id
46+
};
47+
await messageSession.Send("Samples.DelayedDelivery.Server", placeOrder);
48+
Console.WriteLine($"[Defer Message Handling] Sent a PlaceOrder message with id: {id:N}");
49+
#endregion
50+
continue;
51+
case ConsoleKey.D2:
52+
case ConsoleKey.NumPad2:
53+
#region DeferOrder
54+
var placeDelayedOrder = new PlaceDelayedOrder
55+
{
56+
Product = "New shoes",
57+
Id = id
58+
};
59+
var options = new SendOptions();
60+
61+
options.SetDestination("Samples.DelayedDelivery.Server");
62+
options.DelayDeliveryWith(TimeSpan.FromSeconds(5));
63+
await messageSession.Send(placeDelayedOrder, options);
64+
Console.WriteLine($"[Defer Message Delivery] Deferred a PlaceDelayedOrder message with id: {id:N}");
65+
#endregion
66+
continue;
67+
default:
68+
return;
69+
}
70+
}
71+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.29728.190
5+
MinimumVisualStudioVersion = 15.0.26730.12
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{37DA8514-2536-4E76-ABFF-D1E90FB65122}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{5728DE02-C264-4697-B554-DDA5FAD10A47}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{1BEFE50E-24CA-4CAA-8B2C-7F8CD1771CB5}"
11+
EndProject
12+
Global
13+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
14+
Debug|Any CPU = Debug|Any CPU
15+
EndGlobalSection
16+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
17+
{37DA8514-2536-4E76-ABFF-D1E90FB65122}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18+
{37DA8514-2536-4E76-ABFF-D1E90FB65122}.Debug|Any CPU.Build.0 = Debug|Any CPU
19+
{5728DE02-C264-4697-B554-DDA5FAD10A47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20+
{5728DE02-C264-4697-B554-DDA5FAD10A47}.Debug|Any CPU.Build.0 = Debug|Any CPU
21+
{1BEFE50E-24CA-4CAA-8B2C-7F8CD1771CB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22+
{1BEFE50E-24CA-4CAA-8B2C-7F8CD1771CB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
23+
EndGlobalSection
24+
GlobalSection(SolutionProperties) = preSolution
25+
HideSolutionNode = FALSE
26+
EndGlobalSection
27+
EndGlobal
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Build and run the delayed-delivery sample
2+
# Build context should be from the repository root
3+
#
4+
# Example commands:
5+
# docker build -f samples/delayed-delivery/Core_10/Dockerfile -t delayed-delivery-core-10 .
6+
# docker run -it --rm delayed-delivery-core-10
7+
#
8+
# podman build -f samples/delayed-delivery/Core_10/Dockerfile -t delayed-delivery-core-10 .
9+
# podman run -it --rm delayed-delivery-core-10
10+
11+
FROM mcr.microsoft.com/dotnet/sdk:10.0-preview AS build
12+
WORKDIR /app
13+
14+
# Set environment variable for .NET 10 preview builds
15+
ENV DOTNET_SYSTEM_NET_SECURITY_NOREVOCATIONCHECKBYDEFAULT=true
16+
17+
# Copy required config files from repository root
18+
COPY nuget.config .
19+
COPY Directory.Build.props .
20+
COPY BannedSymbols.txt .
21+
22+
# Copy sample solution
23+
COPY samples/delayed-delivery/Core_10/ ./sample/
24+
25+
# Restore and build
26+
WORKDIR /app/sample
27+
RUN dotnet restore
28+
RUN dotnet build --no-restore
29+
30+
FROM mcr.microsoft.com/dotnet/runtime:10.0-preview AS runtime
31+
WORKDIR /app
32+
33+
# Set environment variable for .NET 10 preview builds
34+
ENV DOTNET_SYSTEM_NET_SECURITY_NOREVOCATIONCHECKBYDEFAULT=true
35+
36+
# Install expect and process management tools
37+
RUN apt-get update && apt-get install -y expect procps && rm -rf /var/lib/apt/lists/*
38+
39+
# Create .learningtransport folder for LearningTransport
40+
RUN mkdir -p /app/.learningtransport
41+
42+
# Copy built applications
43+
COPY --from=build /app/sample/Client/bin/Debug/net10.0/ ./Client/
44+
COPY --from=build /app/sample/Server/bin/Debug/net10.0/ ./Server/
45+
COPY --from=build /app/sample/Shared/bin/Debug/net10.0/ ./Shared/
46+
47+
# Copy startup script
48+
COPY samples/delayed-delivery/Core_10/run_sample.sh ./
49+
RUN chmod +x run_sample.sh
50+
51+
CMD ["./run_sample.sh"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Threading.Tasks;
2+
using NServiceBus;
3+
using Microsoft.Extensions.Logging;
4+
#region PlaceDelayedOrderHandler
5+
6+
public class PlaceDelayedOrderHandler(ILogger<PlaceDelayedOrderHandler> logger) :
7+
IHandleMessages<PlaceDelayedOrder>
8+
{
9+
10+
public Task Handle(PlaceDelayedOrder message, IMessageHandlerContext context)
11+
{
12+
logger.LogInformation("[Defer Message Delivery] Order for Product: {Product} placed with id: {Id}", message.Product, message.Id);
13+
return Task.CompletedTask;
14+
}
15+
}
16+
17+
#endregion
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
using NServiceBus;
5+
using Microsoft.Extensions.Logging;
6+
7+
public class PlaceOrderHandler(ILogger<PlaceDelayedOrderHandler> logger) :
8+
IHandleMessages<PlaceOrder>
9+
{
10+
11+
static List<Guid> wasMessageDelayed = [];
12+
13+
#region PlaceOrderHandler
14+
public async Task Handle(PlaceOrder message, IMessageHandlerContext context)
15+
{
16+
if (ShouldMessageBeDelayed(message.Id))
17+
{
18+
var options = new SendOptions();
19+
20+
options.DelayDeliveryWith(TimeSpan.FromSeconds(5));
21+
options.RouteToThisEndpoint();
22+
await context.Send(message, options);
23+
logger.LogInformation("[Defer Message Handling] Deferring Message with Id: {Id}", message.Id);
24+
return;
25+
}
26+
27+
logger.LogInformation("[Defer Message Handling] Order for Product:{Product} placed with id: {Id}", message.Product, message.Id);
28+
}
29+
#endregion
30+
31+
bool ShouldMessageBeDelayed(Guid id)
32+
{
33+
if (wasMessageDelayed.Contains(id))
34+
{
35+
return false;
36+
}
37+
38+
wasMessageDelayed.Add(id);
39+
return true;
40+
}
41+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Microsoft.Extensions.Hosting;
4+
using NServiceBus;
5+
6+
var builder = Host.CreateApplicationBuilder(args);
7+
8+
Console.Title = "Server";
9+
var endpointConfiguration = new EndpointConfiguration("Samples.DelayedDelivery.Server");
10+
endpointConfiguration.UsePersistence<LearningPersistence>();
11+
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
12+
endpointConfiguration.UseTransport(new LearningTransport());
13+
14+
Console.WriteLine("Press any key, application loading");
15+
Console.ReadKey();
16+
Console.WriteLine("Starting...");
17+
18+
builder.UseNServiceBus(endpointConfiguration);
19+
20+
await builder.Build().RunAsync();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net10.0</TargetFramework>
4+
<OutputType>Exe</OutputType>
5+
<LangVersion>preview</LangVersion>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.1" />
9+
</ItemGroup>
10+
11+
<ItemGroup>
12+
<ProjectReference Include="..\Shared\Shared.csproj" />
13+
</ItemGroup>
14+
</Project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+

2+
using System;
3+
using NServiceBus;
4+
#region PlaceDelayedOrder
5+
public class PlaceDelayedOrder :
6+
ICommand
7+
{
8+
public Guid Id { get; set; }
9+
public string Product { get; set; }
10+
}
11+
12+
#endregion
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+

2+
using System;
3+
using NServiceBus;
4+
#region PlaceOrder
5+
public class PlaceOrder :
6+
ICommand
7+
{
8+
public Guid Id { get; set; }
9+
public string Product { get; set; }
10+
}
11+
12+
#endregion

0 commit comments

Comments
 (0)