Skip to content

Commit

Permalink
Merge pull request #2 from Particular/add-clientui
Browse files Browse the repository at this point in the history
Add Main UI projects
WilliamBZA authored Aug 7, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents b56008c + 73f3d83 commit 427bb02
Showing 31 changed files with 801 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/binaries/**/*
7 changes: 7 additions & 0 deletions src/Billing/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[*.cs]

# Justification: Test project
dotnet_diagnostic.CA2007.severity = none

# Justification: Tests don't support cancellation and don't need to forward IMessageHandlerContext.CancellationToken
dotnet_diagnostic.NSB0002.severity = suggestion
20 changes: 20 additions & 0 deletions src/Billing/Billing.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputPath>..\binaries\Billing\</OutputPath>
<ApplicationIcon>failures.ico</ApplicationIcon>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Messages\Messages.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="MassTransit.RabbitMQ" Version="8.2.3" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>
</Project>
20 changes: 20 additions & 0 deletions src/Billing/OrderPlacedHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Billing;

using System.Threading.Tasks;
using MassTransit;
using Messages;

public class OrderPlacedHandler(SimulationEffects simulationEffects) : IConsumer<OrderPlaced>
{
public async Task Consume(ConsumeContext<OrderPlaced> context)
{
await simulationEffects.SimulatedMessageProcessing(context.CancellationToken);

var orderBilled = new OrderBilled
{
OrderId = context.Message.OrderId
};

await context.Publish(orderBilled);
}
}
86 changes: 86 additions & 0 deletions src/Billing/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#pragma warning disable IDE0010
namespace Billing;

using Microsoft.Extensions.Hosting;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

class Program
{
public static IHostBuilder CreateHostBuilder(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});

cfg.ConfigureEndpoints(context);
});

x.AddConfigureEndpointsCallback((name, cfg) =>
{
if (cfg is IRabbitMqReceiveEndpointConfigurator rmq)
{
rmq.SetQuorumQueue();
}
});

x.AddConsumers(Assembly.GetExecutingAssembly());
});

services.AddSingleton<SimulationEffects>();
});

return host;
}

static async Task Main(string[] args)
{
Console.Title = "Failure rate (Billing)";
Console.SetWindowSize(65, 15);

var host = CreateHostBuilder(args).Build();
await host.StartAsync();

var state = host.Services.GetRequiredService<SimulationEffects>();
await RunUserInterfaceLoop(state);
}

static Task RunUserInterfaceLoop(SimulationEffects state)
{
while (true)
{
Console.Clear();
Console.WriteLine("Billing Endpoint");
Console.WriteLine("Press F to increase the simulated failure rate");
Console.WriteLine("Press S to decrease the simulated failure rate");
Console.WriteLine("Press ESC to quit");
Console.WriteLine();

state.WriteState(Console.Out);

var input = Console.ReadKey(true);

switch (input.Key)
{
case ConsoleKey.F:
state.IncreaseFailureRate();
break;
case ConsoleKey.S:
state.DecreaseFailureRate();
break;
case ConsoleKey.Escape:
return Task.CompletedTask;
}
}
}
}
23 changes: 23 additions & 0 deletions src/Billing/SimulationEffects.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Billing;

public class SimulationEffects
{
public void IncreaseFailureRate() => failureRate = Math.Min(1, failureRate + FailureRateIncrement);

public void DecreaseFailureRate() => failureRate = Math.Max(0, failureRate - FailureRateIncrement);

public void WriteState(TextWriter output) => output.WriteLine("Failure rate: {0:P0}", failureRate);

public async Task SimulatedMessageProcessing(CancellationToken cancellationToken = default)
{
await Task.Delay(200, cancellationToken);

if (Random.Shared.NextDouble() < failureRate)
{
throw new Exception("BOOM! A failure occurred");
}
}

double failureRate;
const double FailureRateIncrement = 0.1;
}
Binary file added src/Billing/failures.ico
Binary file not shown.
7 changes: 7 additions & 0 deletions src/ClientUI/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[*.cs]

# Justification: Test project
dotnet_diagnostic.CA2007.severity = none

# Justification: Tests don't support cancellation and don't need to forward IMessageHandlerContext.CancellationToken
dotnet_diagnostic.NSB0002.severity = suggestion
20 changes: 20 additions & 0 deletions src/ClientUI/ClientUI.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputPath>..\binaries\ClientUI\</OutputPath>
<ApplicationIcon>traffic.ico</ApplicationIcon>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MassTransit.RabbitMQ" Version="8.2.3" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Messages\Messages.csproj" />
</ItemGroup>
</Project>
84 changes: 84 additions & 0 deletions src/ClientUI/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#pragma warning disable IDE0010
namespace ClientUI;

using Microsoft.Extensions.Hosting;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

class Program
{
public static IHostBuilder CreateHostBuilder(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((_, services) =>
{
services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});

cfg.ConfigureEndpoints(context);
});

x.AddConfigureEndpointsCallback((name, cfg) =>
{
if (cfg is IRabbitMqReceiveEndpointConfigurator rmq)
{
rmq.SetQuorumQueue();
}
});

x.AddConsumers(Assembly.GetExecutingAssembly());
});

services.AddSingleton<SimulatedCustomers>();
services.AddHostedService(p => p.GetRequiredService<SimulatedCustomers>());
});

return host;
}

static async Task Main(string[] args)
{
Console.Title = "Load (ClientUI)";
Console.SetWindowSize(65, 15);

var host = CreateHostBuilder(args).Build();
await host.StartAsync();

var customers = host.Services.GetRequiredService<SimulatedCustomers>();

await RunUserInterfaceLoop(customers);
}

static Task RunUserInterfaceLoop(SimulatedCustomers simulatedCustomers)
{
while (true)
{
Console.Clear();
Console.WriteLine("Simulating customers placing orders on a website");
Console.WriteLine("Press T to toggle High/Low traffic mode");
Console.WriteLine("Press ESC to quit");
Console.WriteLine();

simulatedCustomers.WriteState(Console.Out);

var input = Console.ReadKey(true);

switch (input.Key)
{
case ConsoleKey.T:
simulatedCustomers.ToggleTrafficMode();
break;
case ConsoleKey.Escape:
return Task.CompletedTask;
}
}
}
}
74 changes: 74 additions & 0 deletions src/ClientUI/SimulatedCustomers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
namespace ClientUI;

using MassTransit;
using Messages;
using Microsoft.Extensions.Hosting;

class SimulatedCustomers(IBus _bus) : BackgroundService
{
public void WriteState(TextWriter output)
{
var trafficMode = highTrafficMode ? "High" : "Low";
output.WriteLine($"{trafficMode} traffic mode - sending {rate} orders / second");
}

public void ToggleTrafficMode()
{
highTrafficMode = !highTrafficMode;
rate = highTrafficMode ? HightTrafficRate : LowTrafficRate;
}

Task PlaceSingleOrder(CancellationToken cancellationToken)
{
var placeOrderCommand = new PlaceOrder
{
OrderId = Guid.NewGuid().ToString()
};

return _bus.Publish(placeOrderCommand, cancellationToken);
}

protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
nextReset = DateTime.UtcNow.AddSeconds(1);
currentIntervalCount = 0;

while (!cancellationToken.IsCancellationRequested)
{
var now = DateTime.UtcNow;
if (now > nextReset)
{
currentIntervalCount = 0;
nextReset = now.AddSeconds(1);
}

await PlaceSingleOrder(cancellationToken);
currentIntervalCount++;

try
{
if (currentIntervalCount >= rate)
{
var delay = nextReset - DateTime.UtcNow;
if (delay > TimeSpan.Zero)
{
await Task.Delay(delay, cancellationToken);
}
}
}
catch (TaskCanceledException)
{
break;
}
}
}

bool highTrafficMode;

DateTime nextReset;
int currentIntervalCount;
int rate = LowTrafficRate;

const int HightTrafficRate = 8;
const int LowTrafficRate = 1;
}
Binary file added src/ClientUI/traffic.ico
Binary file not shown.
Loading

0 comments on commit 427bb02

Please sign in to comment.