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); } }