Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 0 additions & 26 deletions .claude/settings.local.json

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ TestResults/
.idea/
coverage*/
BenchmarkDotNet.Artifacts/
.claude/settings.local.json
2 changes: 1 addition & 1 deletion Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<PackageVersion>3.2.0</PackageVersion>
<CSharpLanguageVersion>12</CSharpLanguageVersion>
<TargetFrameworkVersion>net8.0;net9.0;net10.0</TargetFrameworkVersion>
<SupportedTargetFrameworks>net8.0;net9.0;net10.0</SupportedTargetFrameworks>
<RepositoryUrl>https://github.com/mizrael/OpenSleigh</RepositoryUrl>
<PackageProjectUrl>https://opensleigh.gitbook.io/</PackageProjectUrl>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>$(TargetFrameworkVersion)</TargetFrameworks>
<TargetFrameworks>$(SupportedTargetFrameworks)</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>$(TargetFrameworkVersion)</TargetFrameworks>
<TargetFrameworks>$(SupportedTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<PropertyGroup Condition=" '$(RunConfiguration)' == 'OpenSleigh.Samples.Sample2.API' " />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(TargetFrameworkVersion)</TargetFrameworks>
<TargetFrameworks>$(SupportedTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>$(TargetFrameworkVersion)</TargetFrameworks>
<TargetFrameworks>$(SupportedTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>$(TargetFrameworkVersion)</TargetFrameworks>
<TargetFrameworks>$(SupportedTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>$(TargetFrameworkVersion)</TargetFrameworks>
<TargetFrameworks>$(SupportedTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>$(TargetFrameworkVersion)</TargetFrameworks>
<TargetFrameworks>$(SupportedTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>$(TargetFrameworkVersion)</TargetFrameworks>
<TargetFrameworks>$(SupportedTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
15 changes: 15 additions & 0 deletions samples/OpenSleigh.Samples.PizzaTracker/Messages.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using OpenSleigh.Transport;

namespace OpenSleigh.Samples.PizzaTracker;

public record PlaceOrder(string CustomerName, string PizzaType) : IMessage;

public record PreparePizza : IMessage;

public record BakePizza : IMessage;

public record QualityCheck : IMessage;

public record SendOutForDelivery : IMessage;

public record ConfirmDelivery : IMessage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\OpenSleigh\OpenSleigh.csproj" />
<ProjectReference Include="..\..\src\OpenSleigh.InMemory\OpenSleigh.InMemory.csproj" />
<ProjectReference Include="..\..\src\OpenSleigh.Reporting\OpenSleigh.Reporting.csproj" />
</ItemGroup>

</Project>
91 changes: 91 additions & 0 deletions samples/OpenSleigh.Samples.PizzaTracker/OrderSaga.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using Microsoft.Extensions.Logging;
using OpenSleigh.Transport;

namespace OpenSleigh.Samples.PizzaTracker;

public class OrderSaga :
Saga<OrderState>,
IStartedBy<PlaceOrder>,
IHandleMessage<PreparePizza>,
IHandleMessage<BakePizza>,
IHandleMessage<QualityCheck>,
IHandleMessage<SendOutForDelivery>,
IHandleMessage<ConfirmDelivery>
{
private readonly ILogger<OrderSaga> _logger;

public OrderSaga(ILogger<OrderSaga> logger, ISagaInstance<OrderState> context) : base(context)
{
_logger = logger;
}

public async ValueTask HandleAsync(IMessageContext<PlaceOrder> context, CancellationToken cancellationToken = default)
{
var msg = context.Message;
this.Context.State.CustomerName = msg.CustomerName;
this.Context.State.PizzaType = msg.PizzaType;
this.Context.State.OrderedAt = DateTime.UtcNow;
this.Context.State.Status = "Received";

_logger.LogInformation("🍕 Order received: {PizzaType} for {Customer}", msg.PizzaType, msg.CustomerName);

await SimulateWorkAsync(cancellationToken);
this.Publish(new PreparePizza());
}

public async ValueTask HandleAsync(IMessageContext<PreparePizza> context, CancellationToken cancellationToken = default)
{
this.Context.State.Status = "Preparing";
_logger.LogInformation("👨‍🍳 Preparing {PizzaType}...", this.Context.State.PizzaType);

await SimulateWorkAsync(cancellationToken);
this.Context.State.PreparedAt = DateTime.UtcNow;
this.Publish(new BakePizza());
}

public async ValueTask HandleAsync(IMessageContext<BakePizza> context, CancellationToken cancellationToken = default)
{
this.Context.State.Status = "Baking";
_logger.LogInformation("🔥 Baking {PizzaType} in the oven...", this.Context.State.PizzaType);

await SimulateWorkAsync(cancellationToken);
this.Context.State.BakedAt = DateTime.UtcNow;
this.Publish(new QualityCheck());
}

public async ValueTask HandleAsync(IMessageContext<QualityCheck> context, CancellationToken cancellationToken = default)
{
this.Context.State.Status = "Quality Check";
_logger.LogInformation("✅ Quality check on {PizzaType}...", this.Context.State.PizzaType);

await SimulateWorkAsync(cancellationToken);
this.Context.State.QualityCheckedAt = DateTime.UtcNow;
this.Publish(new SendOutForDelivery());
}

public async ValueTask HandleAsync(IMessageContext<SendOutForDelivery> context, CancellationToken cancellationToken = default)
{
this.Context.State.Status = "Out for Delivery";
_logger.LogInformation("🚗 {PizzaType} is out for delivery to {Customer}!", this.Context.State.PizzaType, this.Context.State.CustomerName);

await SimulateWorkAsync(cancellationToken);
this.Context.State.OutForDeliveryAt = DateTime.UtcNow;
this.Publish(new ConfirmDelivery());
}

public ValueTask HandleAsync(IMessageContext<ConfirmDelivery> context, CancellationToken cancellationToken = default)
{
this.Context.State.Status = "Delivered";
this.Context.State.DeliveredAt = DateTime.UtcNow;

_logger.LogInformation("🎉 {PizzaType} delivered to {Customer}!", this.Context.State.PizzaType, this.Context.State.CustomerName);
this.Context.MarkAsCompleted();

return ValueTask.CompletedTask;
}

private static async Task SimulateWorkAsync(CancellationToken cancellationToken)
{
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
}
}
14 changes: 14 additions & 0 deletions samples/OpenSleigh.Samples.PizzaTracker/OrderState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace OpenSleigh.Samples.PizzaTracker;

public record OrderState
{
public string CustomerName { get; set; } = string.Empty;
public string PizzaType { get; set; } = string.Empty;
public string Status { get; set; } = "Received";
public DateTime OrderedAt { get; set; }
public DateTime? PreparedAt { get; set; }
public DateTime? BakedAt { get; set; }
public DateTime? QualityCheckedAt { get; set; }
public DateTime? OutForDeliveryAt { get; set; }
public DateTime? DeliveredAt { get; set; }
}
41 changes: 41 additions & 0 deletions samples/OpenSleigh.Samples.PizzaTracker/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using OpenSleigh.DependencyInjection;
using OpenSleigh.InMemory;
using OpenSleigh.Reporting;
using OpenSleigh.Samples.PizzaTracker;
using OpenSleigh.Transport;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenSleigh(cfg =>
{
cfg.UseInMemoryTransport()
.UseInMemoryPersistence()
.AddSaga<OrderSaga, OrderState>();
});

builder.Services.AddOpenSleighReporting();

var app = builder.Build();

// OpenSleigh reporting endpoints + OpenAPI document at /openapi/v1.json
app.MapOpenSleighReporting();

// POST /orders — place a new pizza order
app.MapPost("/orders", async (PlaceOrderRequest request, IMessageBus bus) =>
{
var message = new PlaceOrder(request.CustomerName, request.PizzaType);
await bus.PublishAsync(message);

return Results.Accepted(value: new
{
Message = $"Order placed! {request.PizzaType} for {request.CustomerName}.",
Tip = "Use GET /opensleigh/sagas to track all orders, or GET /opensleigh/sagas/{instanceId} for a specific order."
});
})
.WithTags("Orders")
.WithSummary("Place a pizza order")
.WithDescription("Publishes a PlaceOrder message that starts the OrderSaga.");

app.Run();

public record PlaceOrderRequest(string CustomerName, string PizzaType);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"profiles": {
"OpenSleigh.Samples.PizzaTracker": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "http://localhost:5200",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
9 changes: 9 additions & 0 deletions samples/OpenSleigh.Samples.PizzaTracker/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"OpenSleigh": "Information"
}
}
}
Loading
Loading