using System;
using System.Collections.Generic;
namespace Svrnty.CQRS.Events.Abstractions.Sagas;
///
/// Registry for saga definitions.
///
public interface ISagaRegistry
{
///
/// Register a saga definition.
///
/// The saga type.
/// The saga definition.
void Register(SagaDefinition definition) where TSaga : ISaga;
///
/// Get saga definition by type.
///
/// The saga type.
/// The saga definition, or null if not found.
SagaDefinition? GetDefinition() where TSaga : ISaga;
///
/// Get saga definition by name.
///
/// The saga name.
/// The saga definition, or null if not found.
SagaDefinition? GetDefinitionByName(string sagaName);
///
/// Get saga type by name.
///
/// The saga name.
/// The saga type, or null if not found.
Type? GetSagaType(string sagaName);
}
///
/// Saga definition with steps.
///
public sealed class SagaDefinition
{
private readonly List _steps = new();
public SagaDefinition(string sagaName)
{
if (string.IsNullOrWhiteSpace(sagaName))
throw new ArgumentException("Saga name cannot be null or empty", nameof(sagaName));
SagaName = sagaName;
}
///
/// Saga name.
///
public string SagaName { get; }
///
/// Saga steps in execution order.
///
public IReadOnlyList Steps => _steps.AsReadOnly();
///
/// Add a step to the saga.
///
public SagaDefinition AddStep(ISagaStep step)
{
if (step == null)
throw new ArgumentNullException(nameof(step));
_steps.Add(step);
return this;
}
///
/// Add a step using lambdas.
///
public SagaDefinition AddStep(
string stepName,
Func execute,
Func compensate)
{
if (string.IsNullOrWhiteSpace(stepName))
throw new ArgumentException("Step name cannot be null or empty", nameof(stepName));
if (execute == null)
throw new ArgumentNullException(nameof(execute));
if (compensate == null)
throw new ArgumentNullException(nameof(compensate));
_steps.Add(new LambdaSagaStep(stepName, execute, compensate));
return this;
}
}
///
/// Saga step implemented with lambda functions.
///
internal sealed class LambdaSagaStep : ISagaStep
{
private readonly Func _execute;
private readonly Func _compensate;
public LambdaSagaStep(
string stepName,
Func execute,
Func compensate)
{
StepName = stepName ?? throw new ArgumentNullException(nameof(stepName));
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_compensate = compensate ?? throw new ArgumentNullException(nameof(compensate));
}
public string StepName { get; }
public System.Threading.Tasks.Task ExecuteAsync(ISagaContext context, System.Threading.CancellationToken cancellationToken = default)
{
return _execute(context, cancellationToken);
}
public System.Threading.Tasks.Task CompensateAsync(ISagaContext context, System.Threading.CancellationToken cancellationToken = default)
{
return _compensate(context, cancellationToken);
}
}