AbsurdSdk 1.0.1
dotnet add package AbsurdSdk --version 1.0.1
NuGet\Install-Package AbsurdSdk -Version 1.0.1
<PackageReference Include="AbsurdSdk" Version="1.0.1" />
<PackageVersion Include="AbsurdSdk" Version="1.0.1" />
<PackageReference Include="AbsurdSdk" />
paket add AbsurdSdk --version 1.0.1
#r "nuget: AbsurdSdk, 1.0.1"
#:package AbsurdSdk@1.0.1
#addin nuget:?package=AbsurdSdk&version=1.0.1
#tool nuget:?package=AbsurdSdk&version=1.0.1
Absurd.NET
This is a .NET implementation of the Absurd SDK, which has been described at:
1. Setup
To include AbsurdSdk in your project, install the NuGet package using the .NET CLI:
dotnet add package AbsurdSdk
Alternatively, you can use the NuGet Package Manager in Visual Studio:
Install-Package AbsurdSdk
2. Quick Start
We start by defining a IJob, which is going to model an Order Fulfillment Task:
public class FulfillOrderJob : IJob<OrderData, FulfillOrderResult>
{
private readonly PaymentService _paymentService;
private readonly ShippingService _shippingService;
private readonly ILogger<FulfillOrderJob> _logger;
// Define the registration options here
public static TaskRegistrationOptions Options => new()
{
Name = "fulfill-order",
Queue = "orders-queue",
DefaultMaxAttempts = 3
};
// Constructor Injection works perfectly here!
public FulfillOrderJob(
PaymentService paymentService,
ShippingService shippingService,
ILogger<FulfillOrderJob> logger)
{
_paymentService = paymentService;
_shippingService = shippingService;
_logger = logger;
}
public async Task<FulfillOrderResult> ExecuteAsync(TaskContext ctx, OrderData order)
{
_logger.LogInformation("Processing Order {OrderId}", order.OrderId);
// Process the Payment
PaymentResult payment = await ctx.Step("charge-payment", async () =>
{
return await _paymentService.ChargeAsync(order.OrderId, order.Amount);
});
if (!payment.Success)
{
throw new Exception($"Payment failed: {payment.ErrorMessage}");
}
// Wait for Warehouse
_logger.LogInformation("Waiting for pick signal...");
JsonNode pickPayload = await ctx.AwaitEvent(
eventName: $"order-picked:{order.OrderId}",
stepName: "wait-for-picking"
);
// Ship the items
ShippingResult shipment = await ctx.Step("ship-items", async () =>
{
return await _shippingService.ShipAsync(order.OrderId, order.Items);
});
return new FulfillOrderResult { Status = "Fulfilled", Tracking = shipment.TrackingNumber };
}
}
We then register it in the Program.cs like this:
// Register Services
builder.Services.AddSingleton<PaymentService>();
builder.Services.AddSingleton<ShippingService>();
// Build the Absurd Client
builder.Services.AddSingleton<IAbsurd>(sp =>
{
var logger = sp.GetRequiredService<ILogger<Absurd>>();
NpgsqlDataSource dataSource = NpgsqlDataSource.Create(DockerContainers.PostgresContainer.GetConnectionString());
return new Absurd(logger, dataSource);
});
// Register Jobs
builder.Services.RegisterJob<FulfillOrderJob, OrderData, FulfillOrderResult>();
We can then create a Background Worker to poll for Tasks to run:
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
public class SampleOrderWorker : BackgroundService
{
private readonly IAbsurd _client;
private readonly IServiceProvider _provider;
public SampleOrderWorker(IAbsurd client, IServiceProvider provider)
{
_client = client;
_provider = provider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Register Jobs
_client.UseJob<FulfillOrderJob, OrderData, FulfillOrderResult>(_provider);
// Setup the worker to poll the queue
AbsurdWorker absurdWorker = new AbsurdWorker(new WorkerOptions
{
Queue = "orders-queue",
WorkerId = "web-worker-01",
Concurrency = 4,
PollInterval = 0.5,
OnError = ex => Console.WriteLine($"[WORKER ERROR] {ex.Message}")
}, _client);
// Start the worker loop
await absurdWorker.ExecuteAsync(stoppingToken);
}
}
And finally we define two endpoints to create an order and emit events to it:
app.MapPost("/order", async (IAbsurd client, [FromBody] OrderData request) =>
{
// Start the workflow with explicit options
var result = await client.SpawnAsync(new SpawnOptions
{
Queue = "orders-queue",
MaxAttempts = 3
}, "fulfill-order", request);
return Results.Ok(new { Message = "Order started", RunId = result.RunId });
});
app.MapPost("/order/{orderId}/picked", async (IAbsurd client, string orderId, [FromBody] PickingData data) =>
{
// This wakes up the suspended task waiting for "order-picked:{orderId}"
await client.EmitEventAsync(
eventName: $"order-picked:{orderId}",
payload: data,
options: new EmitEventOptions { Queue = "orders-queue" }
);
return Results.Ok(new { Message = "Pick signal sent. Workflow will resume." });
});
app.Run();
To kick off an Order send the JSON Payload to the endpoints:
### Creates Order "ORD-123"
POST https://localhost:5000/order
Content-Type: application/json
Accept-Language: en-US,en;q=0.5
{
"orderId": "ORD-123",
"amount": 99.50,
"items": ["Item A", "Item B"]
}
### Continues running Order "ORD-123"
POST https://localhost:5000/order/ORD-123/picked
{
"picker": "Philipp"
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.