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
  • Loading branch information
WilliamBZA authored Aug 7, 2024
2 parents b56008c + 73f3d83 commit 427bb02
Show file tree
Hide file tree
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.